现代浏览器可以低成本地为两个 CSS 属性制作动画:transform
和 opacity
。如果您为其他任何属性制作动画,则很可能无法达到流畅的 60 帧/秒 (FPS)。这篇文章解释了为什么会这样。
动画性能和帧率
人们普遍认为,在 Web 上为任何内容制作动画时,目标帧率应为 60 FPS。此帧率将确保您的动画看起来流畅。在 Web 上,帧是完成更新和重绘屏幕所需的所有工作所花费的时间。如果每帧未在 16.7 毫秒内完成(1000 毫秒 / 60 ≈ 16.7),则用户将感知到延迟。
渲染管线
为了在网页上显示内容,浏览器必须经过以下顺序步骤
- 样式:计算应用于元素的样式。
- 布局:为每个元素生成几何图形和位置。
- 绘制:填充每个元素的像素。
- 合成:将元素分成图层并将图层绘制到屏幕上。
这四个步骤称为浏览器的渲染管线。
当您在已加载的页面上为某些内容制作动画时,这些步骤必须再次发生。此过程从必须更改的步骤开始,以便允许动画发生。
如前所述,这些步骤是顺序的。例如,如果您为更改布局的内容制作动画,则绘制和合成步骤也必须再次运行。因此,为更改布局的内容制作动画比仅更改合成的内容制作动画成本更高。
动画布局属性
布局更改涉及计算受更改影响的所有元素的几何图形(位置和大小)。如果您更改一个元素,则可能需要重新计算其他元素的几何图形。例如,如果您更改 <html>
元素的宽度,则其任何子元素都可能受到影响。由于元素的溢出方式以及彼此之间的影响,树中更深层的更改有时会导致一直回溯到顶部的布局计算。
可见元素的树越大,执行布局计算所需的时间就越长。
动画绘制属性
绘制是确定元素应以什么顺序绘制到屏幕上的过程。它通常是管线中所有任务中运行时间最长的任务。
现代浏览器中的大多数绘制都是在软件光栅化器中完成的。根据您的应用中的元素如何分组到图层中,除了更改的元素之外的其他元素也可能需要绘制。
动画合成属性
合成是将页面分成图层、将有关页面外观的信息转换为像素(光栅化)并将图层放在一起以创建页面的过程(合成)。
这就是为什么 opacity
属性包含在易于动画处理的事物列表中的原因。只要此属性在其自己的图层中,对它的更改就可以在合成步骤期间由 GPU 处理。基于 Chromium 的浏览器和 WebKit 为任何对 opacity
具有 CSS 过渡或动画效果的元素创建一个新图层。
什么是图层?
通过将要进行动画或过渡处理的内容放置到新图层上,浏览器只需要重绘这些项目,而无需重绘所有其他内容。您可能熟悉 Photoshop 的图层概念,其中包含可以一起移动的一堆元素。浏览器渲染图层与此想法类似。
虽然浏览器在决定哪些元素应位于新图层上方面做得很好,但如果它遗漏了一个元素,则可以使用一些方法来强制创建图层。您可以在如何创建高性能动画中找到有关该内容的信息。但是,创建新图层应谨慎,因为每个图层都会使用内存。在内存有限的设备上,创建新图层可能会导致比您尝试解决的性能问题更大的性能问题。此外,每个图层的纹理都需要上传到 GPU。因此,您很可能会遇到 CPU 和 GPU 之间带宽的限制。
CSS 与 JavaScript 性能
您可能想知道:从性能角度来看,使用 CSS 还是 JavaScript 进行动画更好?
基于 CSS 的动画和 Web Animations(在支持 API 的浏览器中)通常在称为合成器线程的线程上处理。这与浏览器的主线程不同,在主线程上执行样式、布局、绘制和 JavaScript。这意味着,如果浏览器在主线程上运行一些昂贵的任务,这些动画可以继续进行而不会中断。
如本文所述,对变换和不透明度的其他更改在许多情况下也可以由合成器线程处理。
如果任何动画触发了绘制、布局或两者都触发,则主线程将需要执行工作。这对于 CSS 和 JavaScript 动画都是如此,并且布局或绘制的开销可能会使与 CSS 或 JavaScript 执行相关的任何工作相形见绌,从而使问题变得毫无意义。