CSS 动画性能实践与优化

本贴最后更新于 1682 天前,其中的信息可能已经事过境迁

image.png

上次记得发个帖,说会记录一篇关于 CSS 动画性能的 Blog,工作太忙了,一直没时间去记录和实践,总算是完成了!能力有限,当做为社区慢慢做点小力吧doge


随着 JavaScript 以及浏览器的发展,github 开源了很多 动画库进行动画处理,并且每个人似乎都会实现这些 动画库用作现成的动画解决方案。比如 Bounce.js、Anime.js 等等。 CSS 动画及其性能。

适当的了解一下 CSS 动画也是必要的。CSS 基础动画依赖一些 CSS 属性,这些属性通常会在基于 CSS 的动画实现中频繁使用。常用的属性如下:

  • opacity
  • position(absolute /relative)
  • transform(translate)
  • left, right, top, bottom

在比较不同 CSS 属性动画性能之前,首先需要了解浏览器的渲染原理。

渲染树构建、布局及绘制

渲染进程

渲染页面就是让用户看见页面,核心目的在于,转换 HTML、CSS、JS 为用户可交互的 web 页面。渲染进程中主要包含以下线程:

  • Main thread 主线程(负责解析,排版合成,Render Tree 绘制,JavaScript 执行等任务)
  • Compositor thread 合成线程(或者叫排版线程,负责将网页内部位图缓存/纹理输出到窗口的帧缓存,从而把网页显示在屏幕上。在使用 GPU 合成的情况下,也有可能只是产生 GL 绘图指令,然后将绘图指令的缓存发送给 GPU 线程执行)
  • Worker thread 工作线程
  • Raster thread 光栅线程(如果主线程只负责将网页内容转换为绘图指令列表,光栅线程会栅格化每一个图块而且把它们存储在 GPU 的内存中,光栅化的本质是坐标变换、几何离散化,然后再填充)
  • GPU thread GPU 线程(如果使用 GPU 合成,则由 GPU 线程负责执行 GL 绘图指令)

CSS 渲染优化原理

浏览器对页面内容的渲染首先是渲染树的构建:

  • DOM 树与 CSSOM 树合并后形成渲染树(Render Tree)
  • 渲染树只包含渲染网页所需的节点

image.png

image.png

如图,渲染树构建以后,浏览器需要做的动作为:Layout => Paint => Composite,具体含义如下:

  • JavaScript JavaScript 实现动画效果,DOM 元素操作等
  • Recalculate Style(或 Style) 计算将要应用到元素上的样式
  • Layout 创建元素的布局并将其放置在屏幕上
  • Paint 在所有创建的布局中添加像素,更多的是为每个图层创建位图,GPU 使用此位图在屏幕上渲染图层
  • Composite Layers 最后,浏览器在屏幕上创建图层,构造一个图层堆栈。该堆栈的顶视图将看起来像一个完整的网页,其中每个元素都有其自己的位置

Layout 与 Paint 都是耗性能的的过程,特别是 Layout,浏览器需要重新计算样式元素的样式和位置(Recalculate Style )。因此一般对于 CSS 的动画优化,都是尽量减少 Layout 和 Paint 操作,比如尽量避免 table 布局,尽量统一修改样式,而不是串行修改等等,关于 CSS 哪些属性会引起 Layout 与 Paint,可以参考 https://csstriggers.com/

CSS transform vs left-top

这里主要比较的是 transform 与 left-top,类似网站也有 https://lz5z.com/css3_hardware_speedup/

首先编写基础的 HTML:

<body>
    <div class="container">
        <h1>Top/Left Animation</h1>
        <div class="animate animate1"></div>
    </div>
    <div class="container">
        <h1>Transform Animation</h1>
        <div class="animate animate2"></div>
    </div>
</body>

使用 transform

.animate {
  position: absolute;
  top: 100px;
  left: 30px;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: #ff5200;
}
.animate2 {
  animation: move1 3s ease infinite;
}
@keyframes move1 {
  50% {
    transform: translate(100px, 100px);
  }
}

使用 left、top

.animate1 {
  animation: move 3s ease infinite;
}
@keyframes move {
  50% {
    top: 200px;
    left: 130px;
  }
}

性能检测

通过观察上面两种不同的 CSS 动画实现方案,虽然实现了相同的功能,但当我们在 chrome dev-tool 中测量性能指标时,我们会看到两种情况在性能方面的实际差异。

image.png

image.png

通过上面两张图,两个球虽然看起来都在同一层上,但是,当我们以 3D 旋转方式移动该层时,我们发现 transform 动画为另一个球创建了另一个图层。

对于 left-top,因为 Layout 与 Paint 发生在动画的每一帧;而对于 transform,两个图层发送给 GPU,GPU 中 transform 是不会触发 repaint 的,因此动画执行的过程只是两个图层之间的相对移动,这也是 GPU 硬件加速的优势,能够非常快地合成完整的网页。

image.png

image.png

通过突出显示主线程的单个任务,在两种情况下,任务执行的活动是不同的。top-left 会有 Layout , Painting 和 Recalculate style,而 transform 则是由 GPU 执行的单个任务,无需在 DOM 中呈现任何内容即可移动 Composite Layers。

image.png

image.png

通过上面左图(left-top),解释了我们的主线程忙于布局和样式重新计算的确切程度。因此,可以借助 GPU 的强大功能,我们可以使主线程保持空闲状态,这有助于我们提高 web 应用的性能。

分析

通过上面的实践,可以看到 CSS transform 属性实际上是创建了独立的图层,利用 GPU 硬件加速,仅仅发生了 Composite ,实现的平移动画更加平滑,性能也更好。类似的 CSS 属性还有 opacity:

image.png

选择 GPU 加速

上述实践可以看到,CSS transform 属性实际上是创建了独立的图层,触发了硬件加速。此方法的优点是,定期重绘的或通过变形在屏幕上移动的元素,可以在不影响其他元素的情况下进行处理。Sketch、GIMP 或 Photoshop 之类的文件也是如此,各个层可以在彼此的上面处理并合成,以创建最终图像页面。其他类似的属性还有 opacity、filter、will-change,创建新层的最佳方式是使用 will-change 属性。

.demo {
  will-change: transform;
}

对于不支持 will-change 但受益于层创建的浏览器,例如 Safari 和 Mobile Safari,需要使用 3D 变形来强制创建一个新层:

.demo {
  transform: translateZ(0);
}

但需要注意的是不要创建太多层,因为每层都需要内存和管理开销(像素需要存储),GPU 也需要缓存它们以便于后续动画的使用。具体原则如下:

  • 坚持使用 transform 和 opacity 属性更改来实现动画
  • 使用 will-change 或 translateZ 提升移动的元素
  • 避免过度使用提升规则(各层都需要内存和管理开销)

即如无必要,请勿提升元素创建新的图层

总结

从渲染过程以及复合图层(Composite Layers),可以总结一下几点来提升 CSS 动画性能:

  • 尽量避免 reflow 与 repaint
  • CSS 动画尽量使用 transform 与 opacity,比如 animate.css 以及 anime.js 首页提示
  • 保持主线程做最正确的事,尽量避免使用 JS 动画

参考链接


  • CSS

    CSS(Cascading Style Sheet)“层叠样式表”是用于控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。

    196 引用 • 540 回帖 • 1 关注
  • 动画
    7 引用 • 13 回帖
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    247 引用 • 1348 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...