特别声明:此篇文章内容来源于@ANA TUDOR翻译的《Scooped Corners in 2018》一文。
记得@Lea Verou的《CSS Secrets》一书和前几天@Chris Coyier刚发的帖子都介绍了CSS怎么实现元素斜切口的效果。我也尝试着借助Vue的能力,把这种效果构建成一个Vue组件。我把这种效果定义为外切口。而今天将要聊的是与其刚好相反的一个效果:CSS如何实现内凹角的效果。
上图展示的效果就是接下来所要聊的内凹角的效果。也就是说,通过下文的介绍,我们可以知道这种效果是如何做的,而且如何在多个元素上实现这样的内凹角效果。在实现这样的效果当中,将会遇到些什么棘手的问题,又是怎么绕过这些问题的。
最初的想法:box-shadow
对于box-shadow
的属性,想必大家已经非常了解了,如果你从未接触过box-shadow
属性,那么强烈建议您花一点时间去了解一下box-shadow
相关的知识。这样能帮助你更好的理解后续的内容。
我先假设你对box-shadow
有了一定的了解。就算你不了解,也没有关系。你也可以继续后面的内容。假设我们有一个div
的元素。给这个元素添加了一个.box
的类名:
<div class="box"></div>
我们可以显式的给这个.box
元素设置大小或者通过其自己的内容来决定大小,不管是哪种方式,都并不很重要。这里为了简单起见,给其设置了max-width
和min-height
(也是用来设置其大小的)。另外为了能在浏览器中看到效果,其添加了一个outline
的效果,让其看起来有边框的样子。或许你会问,为什么不直接使用border
呢?这个问题留给大家去思考吧,因为不是这篇文章要探讨的内容。
.box {
outline: solid 2px; max-width: 15em; min-height: 10em;
}
接下来,通过伪元素
::before
来创建一个正方形,其边长等于圆角的直径(或者半径--r
的两倍),而且对这个伪元素使用绝对定位。另外为了能在浏览器中看到效果,给这个伪元素添加了一个box-shadow
和background
属性。这只是用来辅助大家理解的,后续会删除的。
:root { --r: 2em; } .box {
position: relative; &::before {
content: '';
position: absolute;
padding: var(--r); box-shadow: 0 0 7px #b53; background: #95a; } }
特别声明:本文的实例代码都来自于@ANA TUDOR的《Scooped Corners in 2018》一文。不同的是我把文章中的Sass变量换成了CSS自定义变量。后续内容如无特别说明,都将类似的做了修改。
这个时候看到的效果如下:
效果如你所期望的一样。接下来对伪元素::before
的border-radius
值设置为50%
,让它成为一个圆形,并且给它设置一个margin
的负值,值等于它的半径--r
。伪元素的中心点和它的父容器.box
的左上角(0,0
)重合。为了让溢出的.box
的伪元素能隐藏起来,需要在.box
中添加一个overflow:hidden
。
:root { --r: 2em; } .box { position: relative; overflow: hidden; &::before { content: ''; position: absolute; padding: var(--r); box-shadow: 0 0 7px #b53; background: #95a; margin: calc(var(--r) * (-1)); border-radius: 50%; } }
现在的结果是这样的:
但这样的效果仍然不是我们想要的。为了达到我们想要的效果,我们需要使用box-shadow
的第四个参数值:阴影扩展半径。如果你想了解box-shadow
添加第四个参数值的效果,可以看下面这个Demo:
你可能已经猜到我们下一步要做什么了。把background
和box-shadow
前三个值(x
和y
轴的偏移值以及模糊半径)设置为0
,并给box-shadow
的扩展半径设置为一个较大的值。
box-shadow: 0 0 0 300px;
下面的这个示例演示了box-shadow
的扩展半径如何让阴影效果覆盖容器更多的面积。
这里用到的一个技巧是让box-shadow
有足够大的扩展半径,这样让伪元素的阴影能覆盖其容器更多的面积。这是非常有意思的一点,给.box
设置box-shadow
以及给其伪元素添加一个半透明的阴影效果。
.box { overflow: hidden; position: relative; margin: .25em auto; min-width: 15em; max-width: 15em; min-height: 10em; border-radius: 1em; &:before { position: absolute; margin: calc(var(--r) * -1); padding: var(--r); border-radius: 50%; box-shadow: 0 0 0 300px rgba(#95a, .75); content: '' } }
其实这是很关键的一步,如果你不仔细看,你或许会认为,那个凹角的效果是box-shadow
实现的。或许你和我一样会纳闷,box-shadow
是如何实现透明凹角的效果。事实并非如此,透明凹角部分是伪元素::before
的