何box-shadow
在CSS中为属性设置动画,而又不引起每一帧的重新绘制,并严重影响页面的性能?简短的答案:你不知道。对变化进行动画处理box-shadow
会损害性能。
有一种简单的方法来模仿相同的效果,但是,只需最少的重绘,就可以使动画以稳定的60 FPS运行:opacity
为伪元素设置动画。
演示
看一下演示并比较我们将探索的两种不同技术。如果两个示例对您来说都一样,那就是关键。唯一的区别是我们如何应用阴影和设置阴影动画。在左边我们动画box-shadow
上hover
,并在右侧我们还加入了一个伪元素用:after
,适用影子说,和动画的opacity
该元素的。
如果您调出开发人员工具并将鼠标悬停在这些项目之一上,则应该看到类似的内容(绿色的条形是油漆;越少越好):
box-shadow
与将卡悬浮在右侧(opacity
为其伪元素的动画)相比,将卡悬浮在左侧(为动画)时,显然会有更多的重绘。
为什么会看到这种效果?在不不断为每一帧触发重绘的情况下,只有很少的CSS属性可以动画,即opacity
和transform
。通过坚持在动画过程中仅更改这两个属性,我们将重新绘制的数量(以及浏览器必须完成的工作)减到最少。
这是两种技术之间的关键区别,它们会去除所有其他布局样式:
/* The slow way */
.make-it-slow {
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
transition: box-shadow 0.3s ease-in-out;
}
/* Transition to a bigger shadow on hover */
.make-it-slow:hover {
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
/* The fast way */
.make-it-fast {
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}
/* Pre-render the bigger shadow, but hide it */
.make-it-fast::after {
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
/* Transition to showing the bigger shadow on hover */
.make-it-fast:hover::after {
opacity: 1;
}
在性能更好的示例中,我们有两层:一层用于盒子,一层用于阴影,并且仅对opacity
阴影层的属性进行动画处理。
分解
有了基本的知识,让我们看一下如何创建演示中展示的3D卡效果。第一步是将阴影移到伪元素,就像我们上面所做的那样。我们还添加所有布局代码来创建卡:
/* All HTML you need is <div class="box"></div> */
/* Create a simple white box, and add the shadow for the initial state */
.box {
position: relative;
display: inline-block;
width: 100px;
height: 100px;
border-radius: 5px;
background-color: #fff;
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
transition: all 0.3s ease-in-out;
}
/* Create the hidden pseudo-element */
/* include the shadow for the end state */
.box::after {
content: '';
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
opacity: 0;
border-radius: 5px;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
transition: opacity 0.3s ease-in-out;
}
请注意,由于我们要为这两个元素设置动画,因此我们要transition
同时为.box
和添加一个.box::after
:transform
for .box
和opacity
for .box::after
。
这些样式给我们一个含蓄的白色盒子box-shadow
。此时,来自的较强阴影.box::after
已完全隐藏,您无法与该框进行交互:
要创建与演示中相同的效果,现在我们需要做的就是放大.box
悬停鼠标,并淡入伪元素及其阴影:
/* Scale up the box */
.box:hover {
transform: scale(1.2, 1.2);
}
/* Fade in the pseudo-element with the bigger shadow */
.box:hover::after {
opacity: 1;
}
而已!将鼠标悬停在框上可以预览效果:
总而言之,这是所有CSS,带有所有供应商前缀,以及一些针对其他custom的自定义缓动:
.box {
position: relative;
display: inline-block;
width: 100px;
height: 100px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 5px;
-webkit-transition: all 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
transition: all 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.box::after {
content: "";
border-radius: 5px;
position: absolute;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
opacity: 0;
-webkit-transition: all 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
transition: all 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.box:hover {
-webkit-transform: scale(1.25, 1.25);
transform: scale(1.25, 1.25);
}
.box:hover::after {
opacity: 1;
}
当然,要实现与简单的动画效果相同的效果,需要大量的CSS box-shadow
,只是要提高性能。何必呢?
即使您的桌面可能box-shadow
没有任何问题地处理动画,您的手机也可能没有问题,甚至在为更复杂的布局制作动画时,您的桌面也可能开始停顿。
只要将过渡和动画设置为transform
和opacity
,就可以确保获得最佳性能,并因此获得最佳的用户体验。