想必写过 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 100px blue;

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 的高阶玩法,你学会了么?

【wWW.adminJS.CN 工作生活学习必备 】

声明:本文仅供个人学习使用,来源于互联网,本文有改动,本文遵循[BY-NC-SA]协议, 如有侵犯您的权益,请联系本站,本站将在第一时间删除。谢谢你

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