Skip to content

Latest commit

 

History

History
44 lines (27 loc) · 3.46 KB

24 分层和合成机制:为什么CSS动画比JavaScript高效?.md

File metadata and controls

44 lines (27 loc) · 3.46 KB

24 | 分层和合成机制:为什么CSS动画比JavaScript高效?

显示器是如何显示图像的

以 60Hz 的刷新率的显示器为例,显示器每秒刷新 60 次,每次刷新都会从 前缓冲区 中读取一帧图像显示在屏幕上。显卡会绘制下一帧图像保存在 后缓冲区 中。当显示器完成一次刷新后,系统会让前缓冲区和后缓交换,这样就完成了一次显示。通常情况下,显卡的更新频率和显示器的刷新频率是一致的。在一些复杂的场景中,显卡处理一张图片的速度会变慢,这样就会造成视觉上的卡顿。

渲染引擎通过重排、重绘、合成等操作,最终会生成一帧图像。这一帧图像会被保存在后缓冲区中,等待显示器刷新时显示在屏幕上。

  • 重排:元素的几何属性发生变化,需要重新计算布局树,然后进行重绘和合成。
  • 重绘:元素的样式属性发生变化,需要重新计算样式,然后进行合成。
  • 合成:将图层合成为一帧图像。

分层和合成机制

为了提升每帧的渲染效率,Chrome 引入了分层和合成的机制。 05-06  渲染流程:HTML、CSS和JavaScript,是如何变成页面的?-2024-03-18-22-37-06

可以把一张网页想象成是由很多个图片叠加在一起的,每个图片就对应一个图层。将素材分解为多个图层的操作就称为分层、最后将这些图层合并到一起的操作就称为合成

当某些元素发生变换,如平移、旋转、缩放 或者透视变换时,这些元素会被单独分成一个图层。这样就可以只对这个图层进行重绘和合成,而不用重新计算整个页面的布局和样式。

需要重点关注的是,合成操作是在合成线程上完成的,这也就意味着在执行合成操作时,是不会影响到主线程执行的。 这就是为什么主线程卡住了,但是 CSS 动画依然能执行的原因。

分块

合成线程会将每个图层分割为大小固定的图块,然后优先绘制靠近视口的图块,大大加速页面的显示速度。

由于从计算机内存上传到 GPU 内存的操作会比较慢。即使只绘制那些优先级最高的图块,也要耗费不少的时间,这涉及到一个很关键的因素——纹理上传

因此,Chrome 又采取了一个策略:在首次合成图块的时候使用一个低分辨率的图片。比如正常分辨率的一半,分辨率减少一半,纹理就减少了四分之三。 直到正常比例的纹理上传完成,再将低分辨率的纹理替换掉。

为什么 CSS 动画比 JavaScript 高效?

当我们使用 JavaScript 来实现动画时,通常是通过改变元素的样式属性来实现的。这样就会触发重排、重绘和合成操作。而当我们使用 CSS 来实现动画时,通常是通过改变元素的 transform 属性来实现的。这样就会触发合成操作。

/* theme.css */
div{ 
    will-change: transform, opacity;
}

渲染引擎会将该元素单独实现一帧,等这些变换发生时,渲染引擎会通过合成线程直接去处理变换,这些变换并没有涉及到主线程,这样就大大提升了渲染的效率。这也是 CSS 动画比 JavaScript 动画高效的原因。

使用 js 改变transform也能享受这个属性带来的优化。