想必写过 CSS 的同学都用过 box-shadow,它能够给元素设置暗影,添加立体作用。

比方说这样:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

但它能做的可不只是暗影,还能够用来做出许多风趣的作用:

比方画蒙娜丽莎:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

画星空:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

这些作用都是 box-shadow 完成的!

是不是不敢相信?

今日咱们就一起研讨下 box-shadow 的高阶用法,来完成这些作用吧。

先过一下根底:

box-shadow 根底

box-shadow 能够设置 5 个值:x偏移量 y偏移量 暗影含糊半径 暗影分散半径 暗影颜色

box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);

比方这个案例:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

暗影中心点 x 轴偏移了 300px,y 轴偏移了 300px:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

那暗影分散半径是啥意思?

看这张图就明白了:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

还有暗影含糊半径:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

再来看下这几个值:

box-shadow: 300px 300px 30px 100pxblue;

x 轴位移、y 轴位移都是指中心点的位移。暗影的半径便是元素的 width/2 + 分散半径 + 含糊半径。

而且 box-shadow 能够设置多个,经过逗号分隔,也便是多重暗影。

这样就能够用来做一些有意思的工作了:

比方把 width、height 设置为 0,然后设置多个暗影:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

width、height 为 0,含糊半径为 0,分散半径为 5px,那整个暗影便是一个 10px * 10px 的方块。

这样设置不同方位的 8 个暗影块便是上面的作用。

假如这样的块多了,是不是就类似像素块那样能展示图画了呢?

没错,蒙娜丽莎便是这么画出来的:

box-shadow 画蒙娜丽莎

全体思路上面已经分析出来了,便是经过 box-shadow 多重暗影设置每个像素块的颜色和方位:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

这儿 width、height 为 0,含糊半径为 0,分散半径为 2px,那总体宽高便是 4px。

而每个块的中心点相距 5px,所以会留下一个距离。

咱们试一下:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

的确,经过这样一个个暗影块就能把蒙娜丽莎画出来。

然后咱们把距离去掉,也便是把分散半径设置大一点:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

现在就连在一起了:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

但这样看起来像素感太强了,咱们给它加点含糊半径,比方设置个 4px:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

这样好多了:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

至此,神秘的蒙娜丽莎的微笑就完成了,只用到了 box-shadow 和一个 div!

这儿是画了蒙娜丽莎,其实各种图片都能画,只要拿到像素数据就行,这个能够经过 canvas 的 getImageData 来拿到。

这儿是一个个摆放的暗影块,那假如随机打算这些暗影块,是不是能够做一些粒子作用呢?

比方星空。

咱们来试一下:

box-shadow 画星空

星空大概是这样的:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

画完蒙娜丽莎,咱们知道了能够经过 box-shadow 多重暗影画出任意多个方块。不过那时是顺序摆放的,现在咱们期望把方位打乱,添加一些随机作用。

怎样随机呢?

css 里的确设置不了随机的东西,可是能够经过预处理器来做到,比方 sass。

咱们经过 sass 来一个写循环生成随机 box-shadow 的函数:

@function multiple-box-shadow($n) {
  $value: '#{random(2000)}px #{random(2000)}px #FFF';
  @for $i from 2 through $n {
    $value: '#{$value} , #{random(2000)}px #{random(2000)}px #FFF';
  }
  @return unquote($value);
}

这段代码是经过 @function 声明 sass 的函数,作用是传入 n,生成随机方位的白色 n 个暗影块。

声明晰一个 $value 的变量作为初始值,然后循环生成 box-shadow 的值加到 $value 里,最终回来 $value,但要用 unquote 把引号去掉。

循环使用 @for $i from xx through yy 的语法,每次循环调用 random 函数生成 2000 内的随机整数。

这样就完成了 n 个随机方位的 box-shadow 的生成逻辑。

然后咱们用一下它:

在 html 里放个 div:

<div id='stars'></div>

给它设置宽高和 box-shadow:

#stars {
  width: 1px;
  height: 1px;
  box-shadow: multiple-box-shadow(700);
}

这儿就没有设置分散半径和含糊半径了,所以暗影块巨细便是元素的宽高。

作用是这样的:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

看下现在的 css:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

的确有随机生成的 700 个 box-shadow 值。

这便是预处理器的作用。

当然,这种逻辑也能够用 JS 来写,运行时生成随机 box-shadow,可是渲染速度上会比 sass 编译期间生成的方案慢许多。

然后咱们让它动起来,加上 animation:

#stars {
    animation: animStar 50s linear infinite;
}
@keyframes animStar{
  from{
    transform: translateY(0px)
  }
  to {		
    transform: translateY(-2000px)
  }
}

前面随机生成的 700 个星星的方位便是 0 到 2000px 的,所以这儿是从 0 运动到 -2000px。

先把时间改短点,改成 3s 看下作用:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

你会发现有段时间下面全是黑的,没有星星,这是为什么呢?

这个很简单想明白:当 translateY 快到 -2000px 的时分,剩余的部分星星不到一屏,其他的方位自然就没有星星了。

怎样解决这个问题呢?

其实这种仍是比较经典的 CSS 问题,比方轮播图的无缝滚动也是同种原因。

解决方法便是在后面再接一个一模一样的,然后位移到了 -2000px 的时分,马上定位到 0 重新开始。这样就无缝了。

咱们经过伪元素来设置这个:

$shadows-small:  multiple-box-shadow(700);
#stars {
  width: 1px;
  height: 1px;
  box-shadow: $shadows-small;
  animation: animStar 3s linear infinite;
  &:after {
    content: " ";
    position: absolute;
    top: 2000px;
    width: 1px;
    height: 1px;
    box-shadow: $shadows-small;
  }
}

注意,这儿要确保两次的 box-shadow 是一样的,所以经过一个变量来保存生成的值,两处都引证这个变量。

这样就无缝了:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

但现在仍是有点假,咱们多加两种不同巨细不同运动速度的星星:

当然,个数也不一样,越大的越少,分别生成 200 和 100个,动画时长分别设置 100s 和 150s:

<div id='stars2'></div>
<div id='stars3'></div>
$shadows-medium: multiple-box-shadow(200);
$shadows-big:    multiple-box-shadow(100);
#stars2 {
  width: 2px;
  height: 2px;
  box-shadow: $shadows-medium;
  animation: animStar 100s linear infinite;
  &:after {
    content: " ";
    position: absolute;
    top: 2000px;
    width: 2px;
    height: 2px;
    box-shadow: $shadows-medium;
  }
}
#stars3 {
  width: 3px;
  height: 3px;
  box-shadow: $shadows-big;
  animation: animStar 150s linear infinite;
  &:after {
    content: " ";
    position: absolute;
    top: 2000px;
    width: 3px;
    height: 3px;
    box-shadow: $shadows-big;
  }
}

看下作用:

box-shadow 高阶玩法:纯 CSS 画蒙娜丽莎和粒子星空

星空的感觉是不是就出来了!

不过现在的代码还有点不高雅,star 的样式重复写了 3 次,已然用了 sass,那能够把它抽成一个 mixin 来复用:

@mixin stars($size, $duration, $boxShadow) {
  width: $size;
  height: $size;
  background: transparent;
  box-shadow: $boxShadow;
  animation: animStar $duration linear infinite;
  &:after {
    content: " ";
    position: absolute;
    top: 2000px;
    width: $size;
    height: $size;
    background: transparent;
    box-shadow: $shadows-small;
  }
}

三处样式只要 include 这个 mixin,传入参数即可:

#stars {
  @include stars(1px, 50s, $shadows-small);
}
#stars2 {
  @include stars(2px, 100s, $shadows-medium);
}
#stars3 {
  @include stars(3px, 150s, $shadows-big);
}

代码高雅了许多!

悉数 scss 代码如下:

@function multiple-box-shadow($n) {
  $value: '#{random(2000)}px #{random(2000)}px #FFF';
  @for $i from 2 through $n {
    $value: '#{$value} , #{random(2000)}px #{random(2000)}px #FFF';
  }
  @return unquote($value);
}
$shadows-small:  multiple-box-shadow(700);
$shadows-medium: multiple-box-shadow(200);
$shadows-big:    multiple-box-shadow(100);
html {
  height: 100%;
  background: #000;
  overflow: hidden;
}
@mixin stars($size, $duration, $boxShadow) {
  width: $size;
  height: $size;
  background: transparent;
  box-shadow: $boxShadow;
  animation: animStar $duration linear infinite;
  &:after {
    content: " ";
    position: absolute;
    top: 2000px;
    width: $size;
    height: $size;
    background: transparent;
    box-shadow: $shadows-small;
  }
}
#stars {
  @include stars(1px, 50s, $shadows-small);
}
#stars2 {
  @include stars(2px, 100s, $shadows-medium);
}
#stars3 {
  @include stars(3px, 150s, $shadows-big);
}
@keyframes animStar{
  from{
    transform: translateY(0px)
  }
  to {		
    transform: translateY(-2000px)
  }
}

总结

box-shadow 咱们一般用来做暗影,但其实也能够用来做一些风趣的作用。

暗影块的巨细是由元素宽高、分散半径、含糊半径这些决议的。

经过多重暗影顺序摆放暗影块能够到达像素块的作用,画出蒙娜丽莎或许其他任意的图片。

也能够经过 sass 预处理器随机生成不同方位的暗影块来做出粒子作用,比方星空。

除了能够随机生成样式外,还能够经过 sass 的 mixin 来抽离相似的代码,多处复用,让 css 代码更高雅。这便是预处理器的含义。

box-shadow 的高阶玩法,你学会了么?