【译】不止是 box-shadow,用 css 能表现的各种影子,以及各种陷阱!

4,351 阅读9分钟
正在从事网页设计者或者从事前端的小伙伴们,一定会有想要加阴影的时候吧。
那么阴影会是什么样的表现,以及需要那些参数,你了解的多少呢?

一般要加阴影,就会想到要用 css 的 box-shadow 吧,实际上还有好几种表现方式。暂且不说网页,在逐年变化的设计潮流里,怎么处理阴影也是很重要的一个课题。

就比如说早些时间流行的长投影,以及今年开始流行的 Neumorphism(拟态)什么的。其独特的影子表现手法,也是各显千秋。

▼ 用 css 制作的 长投影,和 拟态 的例子:

在这篇文章,将会介绍各种影子的技术手段,以及各个参数。

box-shadow 基础

用 css 添加阴影,最最最最最容易想到的就是 box-shadow 了。

复习 box-shadow 参数

首先看一下 box-shadow 的参数。

就算最基本的 box-shadow,也是可以实现的各种效果。

/* 1. 基础的 box-shadow */
.basic1 {
  box-shadow: 0 10px 25px 0 rgba(0, 0, 0, .5);
}
/* 2. 使用 inset 添加内阴影。圆也没问题。 */
.basic2 {
  box-shadow: inset 0 10px 25px 0 rgba(0, 0, 0, .5);
}
/* 3. 可以指定任意的颜色以及透明度 */
.basic3 {
  box-shadow: 0 10px 25px 0 rgba(60, 194, 235, 0.5);
}
/* 4.通过偏移量,写出像 border 一样的效果 */
.basic4 {
  box-shadow: 15px 15px 0px 0 rgb(60, 194, 235);
}

多个阴影重叠

我们可以写任意个阴影,并且重叠,来看看下面的例子吧!

/* 1. 通过 6 层阴影重叠,实现更加真实的投影 */
.layer1 {
  box-shadow:
    0 1.9px 2.5px rgba(0, 0, 0, 0.057),
    0 5px 6.1px rgba(0, 0, 0, 0.076),
    0 10.1px 11.4px rgba(0, 0, 0, 0.086),
    0 19.2px 19.8px rgba(0, 0, 0, 0.092),
    0 38.4px 34.8px rgba(0, 0, 0, 0.1),
    0 101px 74px rgba(0, 0, 0, 0.13);
}
/* 2.  影子朝不同的方向,指定不同颜色 */
.layer2 {
  box-shadow:
    -10px 10px 25px rgba(230, 180, 15, 0.9),
    10px -10px 25px rgba(8, 131, 161, 0.9)
}
/* 3. 利用多层重叠,让阴影看起来像很多层纸 */
.layer3 {
  box-shadow:
    0 20px 0 -10px rgb(198, 224, 231),
    0 40px 0 -20px rgb(105, 171, 209),
    0 60px 0 -30px rgb(27, 115, 165)
}

通过多层的阴影重叠,是一种常见的用法。就比如在 google 浏览器的弹窗,随处可见。

非 box-shadow,伪元素模拟的阴影

box-shadow 虽然很简单,但也有实现不了的场景。 下图的左边,是蓝色的 box-shadow 实现的阴影。下图右边是伪元素实现的阴影,右边的是不是看起来更加真实呢?

demo 示例🔗

解析伪元素模拟阴影

box-shadow 只是给加上指定颜色的 blur(模糊)效果,影子的颜色跟背景组合在一起的话,看起来不太自然。 如果要实现更加真实的阴影,我们可以利用 css 的 filter 跟 mix-blend-mode 配合。(不要跟我谈 ie,那是什么,可以吃吗!)

.box::after {
  /* 通过伪元素设置相同的大小,并且在背面表示 */
  content: '';
  display: block;
  position: absolute;
  z-index: -1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;

  /* ①添加颜色 */
  background-color: rgb(42, 159, 226);
  /* ②添加模糊*/
  filter: blur(15px);
  /* ③调整位置和大小 */
  transform: translateY(10px) scale(1.05);
  /* ④添加混合效果 */
  mix-blend-mode: multiply;
}

跟只有一行的 box-shadow 比起来确实麻烦了不少,但是伪元素可以调整大小,加上任意的 filter,可以实现更加自由的组合。 我们来看几个例子吧!

给渐变色或者照片加上阴影

跟 box-shadow 不同,伪元素可以投影渐变图像以及任意的图片。这样模糊的阴影,画面的印象更深!

改变混合效果

出了普通的投影之外,我们还可以试着改变不同的混合效果。

上面的例子,是用 color-dodge 表象出来发光的效果,另外可以利用 color-burn、 hard-light 等等表象出各式各样的效果。

另一种阴影 dorp-shadow

还有一个我们不要忽视的是 drop-shadow。box-shadow 只能够给元素的四个边角加上投影,但 drop-show 可以跟实际内容结合来产生投影。实际内容是指位图、svg 图、文本、子元素等等,基本上所有的东西都可以。如果只想给看到的东西、直接给其加上阴影的话,那就使用 drop-shadow 吧!

drop-shadow 跟 box-shadow 写法不同之处

drop-shadow 是属于 css 的 filter 的一种。虽然参数少了几个,但跟 box-shadow 基本一致。

有几个注意点:

  1. 就算跟 box-shadow 设定成同样的值,drop-shadow 看起来会更加模糊。
  2. drop-shadow 不可以使用 inset。
  3. drop-shadow 算上 x、y 的偏移量就只有 4 个参数,设定错了会没效果。
  4. drop-shadow 不支持 ie。虽然可以通过(filter: progid:DXImageTransform.Microsoft.DropShadow),这里不做介绍。

下图是比较同样值,box-shadow 跟 drop-shadow 的比较,如果最求设计稿跟画面高度一致的话,可以注意一下。

drop-shadow 可以解决阴影重叠

接下来这个例子是 css animation 制作的 loading 效果。用旋转着的 8 个小圆圈来模仿 windows 加载动画的效果。

两个示例都是给加的左侧阴影、box-shadow 的表现挺差强人意的:

  • 因为给每个元素加上了阴影,所以看起来不像是一个整体。
  • 如果加上了动画的话,会更加的混乱。

左侧是给每个子元素加上 box-shadow 的,而右边是给子元素的父元素加上的 drop-shadow,这是无法避免的,这里稍微提醒一下。

总而言之,drop-shadow 支持投影的重叠。

阴影的内幕 - 陷阱与对策

box-shadow 跟 drop-shadow,背后是浏览器复杂的渲染运算,因此会有很多坑,这里,我们再去试着跟 animation 组合,看看会有哪些坑,并且会介绍一下应对策略。

陷阱1:卡顿(Safari)

在元素 hover 状态下加上 transition 的投影动画,chrome、safari 表现不同,safari 会稍微有点卡顿。

这个现象的产生原因,主要是因为变更了 box-shadow 的模糊半径。虽然不能够达到完全一致的效果,但是如果注重流畅的效果的话,可以替换成改变颜色透明度。

/* 1. 改变模糊半径 */
.box1{
  transition: box-shadow 2s ease-out, transform 2s ease-out;
}
.box1:hover {
  box-shadow: 0 15px 10px 5px rgb(0, 0, 0);
  transform: translateY(-10px);
}

/* 2. 只改变透明度 */
.box2{
  transition: box-shadow 2s ease-out, transform 2s ease-out;
  box-shadow: 0 15px 10px 5px rgba(0, 0, 0, 0);
}
.box2:hover {
  box-shadow: 0 15px 10px 5px rgba(0, 0, 0, 1);
  transform: translateY(-10px);
}

陷阱2:hover 的阴影会被溢出隐藏(Safari)

hover 的状态下,drop-shadow 也会出问题。 溢出会被裁切掉。

在 safari 改变 drop-shadow 的话,内部会重新渲染产生了这个问题。虽然有点麻烦,但是如果实在需要的话,我们需要给元素加上足够空间的 padding。

.ok {
  display: inline-block;
  font-size: 0;
  /* 添加足够空间的padding */
  padding: 100px; 
  filter: drop-shadow(0 0px 3px rgba(0, 0, 0, .9));
}
.ok:hover {
  filter: drop-shadow(0 10px 60px rgba(0, 0, 0, .9));
}

陷阱3: 动画过程中,阴影无法显示(Safari)

这个也是在 safari 的现象。

用三个 div 配合 transition 动画做了一个菜单,如果给 icon 全体都加上 dorp-shadow 的话,在 safari 里面阴影会消失。

以下是这个现象发生的条件:

  • 多个子元素加上了 transition 跟 transform。
  • 两个以上的子元素使用了 drop-shadow。

多个阴影重叠的手法在设计中会经常出现,如果直接复制的话,说不定就达成了条件。

陷阱4: 添加了太多阴影动画的话,浏览器会难消化(Chrome、Firefox)

最后一个是在 chrome、firefox 出现的陷阱。我们试着给 100 个 div 加上阴影、配合 css 的 animation。进行下面 3 种实验

  1. 给每个子元素加上 box-shadow。
  2. 给每个子元素加上 drop-shadow。
  3. 给父元素加上 drop-shadow。

可能机器个体性能不同,写这片文章的时候使用的平台是 iMac(iMac 5K, 27-inch, 2019)

demo 示例🔗

浏览器每个子元素加上 box-shadow给每个子元素加上 drop-shadow给父元素加上 drop-shadow
Chrome(80)超慢
Safari(13.1)一般
Firefox(74)

每个浏览器的倾向都不同。特别是 chrome 的 drop-shadow。如果给元素增加到 200 个的话,只剩 10 fps 了。

safari从一开始就用 gpu 处理渲染了,而 chrome 的话会让 cpu 爆炸。如果是这样的场景的话,那么各个浏览器得好好确认了。不过,现在应该很难见到 box-shadow 加上 animation 这种场景了吧。

总结

这片文章介绍了 box-shadow、drop-shadow、已经伪元素配合 css filter 模拟的阴影的各种手段。特别是在使用动画的时候,会有各种不一样的效果,需要注意一小下,只要遵守这些隐藏规定的话,css 表现阴影还是挺强的。期待您掌握 css 的阴影技术,下次在实际应用场景上发挥地更加出色。

译者记录

在了解这片文章之前,我还是只知道 box-shadow 可以产生阴影,完全没有注意到 drop-shadow 也可以做投影。元素模拟倒是有知道一点,但是表现的这么出色,倒是很少见。

偶然间发现这片文章,介绍了阴影的各种手法,每个点都很细致的介绍到了,非常的不错,特意花了点时间翻译了一下,分享给大家,希望能够派的上用场,让大家对 css 的阴影能够有更加深刻的理解。

原文地址:ics.media/entry/20040…

作者:松本 ゆき

翻译:view