上一篇文章学习了重绘和回流对页面性能的影响,是从比较宏观的角度去优化 Web 性能,本篇文章从每一帧的微观角度进行分析,来学习 CSS3 硬件加速的知识。
CSS3 硬件加速又叫做 GPU 加速,是利用 GPU 进行渲染,减少 CPU 操作的一种优化方案。由于 GPU 中的 transform 等 CSS 属性不会触发 repaint,所以能大大提高网页的性能。
我做了一个页面,左边元素的动画通过 left/top 操作位置实现,右边元素的动画通过 transform: translate
实现,你可以打开 chrome 的 “Paint flashing” 查看,绿色部分是正在 repaint 的内容。
从 demo 中可以看到左边的图形在运动时外层有一圈绿色的边框,表示元素不停地 repaint,并且可以看到其运动过程中有丢帧现象,具体表现为运动不连贯,有轻微闪动。
之前学习 flash 的时候,就知道动画是由一帧一帧的图片组成,在浏览器中也是如此。我们首先看一下,浏览器每一帧都做了什么。
浏览器在获取 render tree(详细知识可以查看Web性能优化-页面重绘和回流(重排))后,渲染树中包含了大量的渲染元素,每一个渲染元素会被分到一个图层中,每个图层又会被加载到 GPU 形成渲染纹理。GPU 中 transform 是不会触发 repaint 的,这一点非常类似 3D 绘图功能,最终这些使用 transform 的图层都会由独立的合成器进程进行处理。
过程如下:
render tree -> 渲染元素 -> 图层 -> GPU 渲染 -> 浏览器复合图层 -> 生成最终的屏幕图像。
TIPS: chrome devtools 中可以开启 Rendering 中的 Layer borders 查看图层纹理。 其中黄色边框表示该元素有 3d 变换,表示放到一个新的复合层(composited layer)中渲染,蓝色栅格表示正常的 render layer。
在文章开始给出的例子中,我们也可以开启 Layer borders,可以观察到,使用 transform: translate
动画的元素,外围有一个黄色的边框,可知其为复合层。
在 GPU 渲染的过程中,一些元素会因为符合了某些规则,而被提升为独立的层(黄色边框部分),一旦独立出来,就不会影响其它 DOM 的布局,所以我们可以利用这些规则,将经常变换的 DOM 主动提升到独立的层,那么在浏览器的一帧运行中,就可以减少 Layout 和 Paint 的时间了。
哪些规则能让浏览器主动帮我们创建独立的层呢?
关于 z-index 导致的硬件加速的问题,可以查看这篇文章 CSS3硬件加速也有坑!!
CSS 中的以下几个属性能触发硬件加速:
如果有一些元素不需要用到上述属性,但是需要触发硬件加速效果,可以使用一些小技巧来诱导浏览器开启硬件加速。
.element {
-webkit-transform: translateZ(0);
-moz-transform: translateZ(0);
-ms-transform: translateZ(0);
-o-transform: translateZ(0);
transform: translateZ(0);
/**或者**/
transform: rotateZ(360deg);
transform: translate3d(0, 0, 0);
}
注意:我在不同的资料中查到的 transform 是否能触发硬件加速的结果不同,自己测试后,发现结果是可以。
(1)过多地开启硬件加速可能会耗费较多的内存,因此什么时候开启硬件加速,给多少元素开启硬件加速,需要用测试结果说话。 (2)GPU 渲染会影响字体的抗锯齿效果。这是因为 GPU 和 CPU 具有不同的渲染机制,即使最终硬件加速停止了,文本还是会在动画期间显示得很模糊。