最近在优化页面动画效果时,和同事探讨到了页面动画卡顿的问题,即使大致了解CSS实现的动画会比JS性能更佳,卡顿更少,但是一直没有深究这样的问题原理是什么。这次在优化过程中,发现即使使用CSS动画,但是在使用height,width,margin,padding作为transition的值的时候,依然会卡顿,但是使用CSS transform就会有明显的改善。问题类似就不赘述了,在参考中附一个类似的问题。
这里主要讲一讲CSS到底哪些动画效果帧数高,性能好,背后的原理到底又是什么。

CSS 和 JS 怎样实现页面动画?

CSS和JS都可以实现一些网页的动画效果,比如CSS transitions/animations 和 JavaScript-based animations (using requestAnimationFrame())

CSS transitions 和 animations

CSS transitions 提供了一种简单的方式在现有样式和最终CSS状态之间实现动画效果。即使元素仍然在变化过程中,新的transition会从现在的样式开始变化而不是直接跳到结束时的CSS状态。
image.png

CSS animations允许开发者在一系列开始值和终止值之间设定动画,它包含两个部分,一种描述CSS animation的样式,以及定义多个关键帧以及每个关键帧中元素的属性值

requestAnimationFrame

requestAnimationFrame告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
和CSS transitions 和 animations一样,requestAnimationFrame()在当前Tab被push到后台时,也会暂停。

CSS真的比JS实现的动画快么?

先说结论,不是的。
在大多数情况下,其实CSS和JS实现的动画性能其实都是差不太多的,甚至有些JS动画库宣称他们的性能是要强过CSS原生动画的。这种情况之所以会发生,是因为CSS transitions/animations会在repaint事件发生前,在UI主进程中重新采集元素的样式。这和requestAnimationFrame() callback采用的形式其实基本上一样。
所以如果animations是发生在主进程中,其实性能上并没什么卵差别的。

为啥CSS animations仍是更棒的选择?

CSS animations更棒的关键在于,只要我们希望设置动效的属性并没有触发reflow/repaint操作,我们就可以将塑造元素的操作移除主进程。浏览器只需要一次生成这个元素的位图,并在动画开始的时候将它提交给GPU去处理,这就会显著提升处理性能,尤其是在移动设备上。之后,浏览器不需要再做任何布局、 绘制以及提交位图的操作。从而,浏览器可以充分利用 GPU 的特长去快速地将位图绘制在不同的位置、执行旋转或缩放处理。
image.png

Platform/GFX/OffMainThreadCompositing https://wiki.mozilla.org/Plat...

这其中,最常见的用法就是 CSS transform

在 CSS triggers(https://csstriggers.com/)
这张表里,我们可以看到transform是不会在Layout和Paint层面作trigger的
image.png
image.png
当然,也可以发现目前WebKit内核在CSS triggers上和Gecko内核仍然是有区别的,这也就不排除IOS和Android设备在移动端的动画性能上,同样的实现方式仍然会有体验上的差别。

参考:

  1. CSS and JavaScript animation performance https://developer.mozilla.org...
  2. CSS3动画卡顿性能优化解决方案 https://segmentfault.com/a/11...
  3. Using CSS transitions https://developer.mozilla.org...
  4. Using CSS animations https://developer.mozilla.org...

数据里奥斯
95 声望1 粉丝

数字生活家 |软件工程师