box-shadow详解

10,156 阅读6分钟

box-shadow是css中最基础的属性之一,都知道box-shadow可以生成阴影,那么它的生成阴影的过程是什么呢?以及如何用box-shadow制作不同的效果呢?相信你看完本文,会有自己的答案!

一、基本概念

首先看下MDN上的定义:

box-shadow 以由逗号分隔的列表来描述一个或多个阴影效果。该属性可以让几乎所有元素的边框产生阴影。如果元素同时设置了 border-radius ,阴影也会有圆角效果。多个阴影的z-ordering 和多个 text shadows 规则相同(第一个阴影在最上面)。

基本用法:

基本用法

值的说明:

值的说明

简单说明:

  • inset关键字,可设可不设,inset代表阴影是向内的
  • color,这个值可设可不设,但是因为用户代理不同,阴影的颜色的默认值也会不同,所以建议统一设置
  • 可以给一个元素设置多个box-shadow,每一组用逗号“,”隔开,并且越靠前的优先级越高,会覆盖后面的阴影

二、从一个简答的例子开始,了解box-shadow的生成过程

html:

<div class="box">
<div>

css:

.box {
    width: 300px;
    height: 200px;
    background-color: yellowgreen;
    box-shadow: 30px 50px 20px #000;
}
  1. 首先在box元素的上层生成一个同box大小,形状完全相同的阴影,这里为矩形,颜色为#000

注意,此时阴影是在元素的上层

  1. 根据offset-x和offset-y,将阴影逐渐从上层移动出来,得到的结果就是,阴影向右移动30px,向下移动50px
  1. 这里我们设置了一个20px的模糊半径,此时就会以四个方向,每个方向的阴影边缘线为中心,左右扩展10px的区域,共20px,共同组成这个阴影区域,如下图:

这里只用右侧举例,从阴影边缘开始,左右各一半高斯模糊,共同组成模糊的半径,那么四个方向都会产生模糊效果

  1. 现在只剩下最后一步,就是将阴影与元素重叠的区域全部裁剪掉,如下图虚线内容

裁剪后就是我们最终的结果:

这里唯一需要注意的是,阴影本质是在元素上方的,并且最终被裁剪掉,而不是出现在元素的下方,所以从这点来说,是不同于text-shadow的,因为text-shadow是出现在元素下方的,并且不会有裁剪的过程,证明起来也很简单,分别给元素和字体设置透明就好了。 div设置透明颜色 很明显下面什么也没有

三、进一步了解参数

offset

这个属性比较简单,只用考虑是否为inset就行了

  • 非inset:

    正负:阴影移动的方向。向右,向下为正值。

    大小:阴影移动的距离

  • inset:

    正负:表示从哪条边出现阴影。正:左上,负:右下

    大小:表示阴影在某一侧的长度

具体内容,可以看下面inset的例子

blur-radius

高斯模糊的半径,从上面例子就可以了解到了。用来设置阴影边缘的模糊的。 不可以为负值。

spread-radius

我们了解了阴影是如何生成的,以及高斯模糊半径的作用范围,现在我们聊一下另一个属性:spread-radius,这个属性称之为扩展半径,扩展二字就很能说明问题了,其实它就是扩展的阴影面积的大小。一开始,阴影的面积是等于元素的尺寸的,我们的模糊半径也只能从这个阴影的边缘两侧开启高斯模糊,当我们想修改这个阴影的面积时,就用到了spread-radius属性。spread-radius表示四个方向增大或者减小的尺寸。 我们修改上面的box-shadow参数,增加扩展半径,去除模糊半径,利于观察

box-shadow: 30px 50px 0 30px #000;
  • 绿色:box元素自身的尺寸
  • 灰色:未设置扩展半径的阴影区域
  • 黑色边框:扩展半径的尺寸
  • 虚线区域:每一侧增加的扩展半径 30px 上图其实已经很能说明问题了,黑色边框的高度正好就是30px,正好四个方向,每一个方向都增大30px的长度,那么阴影水平和垂直都增加(30px + 30px)60px 因为扩展半径增大了阴影的面积,所以,模糊半径也会从增大后的阴影边缘向两侧模糊,所以如果设置了模糊半径,效果如下:
box-shadow: 30px 50px 10px 30px #000;

spread-radius 负值

是的,spread-radius是可以设置负数值的,会在水平和垂直方向减小阴影的尺寸。 在后续的场景中,我会详细讲解这个负数值的应用

inset

inset属性在某些场合也用到很多,原理相同,但是细节有些不一样 修改上上面的参数为inset

box-shadow: inset 30px 50px 0 0 #000;

当修改offset为负值时:

box-shadow: inset -30px -50px 0 0 #000;

由上面可以看出,在inset模式下

  • offset会选择从哪条边,渲染阴影,这点是不同的
  • spread-radius和offset值配合起来的最大值也不能超出元素的尺寸,因为如果超出元素,那么设置这个元素就没有意义了,因为它已经看不见了

四、补充

  • 阴影是不会作为内容计算的,这就意味着: 父元素不会因为阴影产生滚动条 不会对布局产生影响,所以阴影可能会覆盖其他元素

  • 为什么叫box-shadow

    1. 表明这只是对盒子的阴影,跟盒子里面的内容没有关系,并不是真正意义的单侧光源阴影,从上面阴影的生成过程就已经就可以了解到,第一步就是生成等同box的阴影,并不会考虑盒子内部是否透明,内部透明是否也能产生阴影,因为阴影会根据盒子裁剪重合的部分。 这也就是它和drop-shadow的区别,后面的应用会具体比较描述。

    2. 阴影的大小依据,是根据border-box的。 上面的案例,一直没有设置padding和border,所以看不出来,我们可以设置padding,border试试:

      .box {
          width: 300px;
          height: 200px;
          background-color: yellowgreen;
          box-shadow: 30px 50px 0 0 #000;
          background-clip: content-box;
          padding: 20px;
          border: 30px solid red;
      }
      

      可以看出,阴影的大小是border-box的大小,而不是content-box,包括设置border-radius,也是如此,与border-box保持一致

      对于inset,阴影也是从border内边缘扩展

  • 最后,最重量级的图,w3c给出的box-shadow的示意图 一开始,没展示的原因是,怕一上来就展示大家可能一头雾水,如果你看到这里,再看到这个图,我相信你会豁然开朗。

参考文章:包含但不限于以下文章,如有侵权请联系

 https://www.zhangxinxu.com/wordpress/2016/05/css3-filter-drop-shadow-vs-box-shadow/

 https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow

下一节,我们将一起了解box-shadow的应用