积木区发现一个诡异的现象,在一些低端机型上,使用 translate3d
反而更卡?来看看 Composite(合成层)
的细节。
Chrome Rendering
Web 展示流程
JavaScript => Style => Layout => Paint => Composite
- JavaScript:我们会使用 JavaScript 来实现一些视觉变化的效果。比如做一个动画或者往页面里添加一些 DOM 元素等。
- Style:计算样式,这个过程是根据 CSS 选择器,对每个 DOM 元素匹配对应的 CSS 样式。这一步结束之后,就确定了每个 DOM 元素上该应用什么 CSS 样式规则。
- Layout:布局,上一步确定了每个 DOM 元素的样式规则,这一步就是具体计算每个 DOM 元素最终在屏幕上显示的大小和位置。web 页面中元素的布局是相对的,因此一个元素的布局发生变化,会联动地引发其他元素的布局发生变化。
- Paint:绘制,本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个 DOM 元素所有的可视效果。这个绘制过程是在多个层上完成的。
- Composite:渲染层合并,对页面中 DOM 元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。
合成层成因
某些特殊的渲染层会被认为是合成层(Compositing Layers),合成层拥有单独的 GraphicsLayer,而其他不是合成层的渲染层,则和其第一个拥有 GraphicsLayer 父层公用一个。
直接原因
- 覆盖在 video 元素上的视频控制栏
- 在 DPI 较高的屏幕上,fix 定位的元素会自动地被提升到合成层中。
- 有 3D transform
- backface-visibility 为 hidden
- animation 或者 transition(效果未开始或结束后,提升合成层会失效)
- will-change 设置为 opacity、transform、top、left、bottom、right
后代元素原因
- 有合成层后代同时本身有 transform、opactiy(小于 1)、mask、fliter、reflection 属性
- 有合成层后代同时本身 overflow 不为 visible
- 有合成层后代同时本身 fixed 定位
overlap 重叠原因
- 重叠或者说部分重叠在一个合成层之上
- filter 效果同合成层重叠
- transform 变换后同合成层重叠
- overflow scroll 情况下同合成层重叠
- 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)
主动提升
提升合成层的最好方式是使用 CSS 的 will-change 属性。will-change 设置为 opacity、transform、top、left、bottom、right 可以将元素提升为合成层。
1
2
3
#target {
will-change: transform;
}
不支持 will-change 属性的浏览器,目前常用的是使用一个 3D transform 属性来强制提升为合成层。
1
2
3
#target {
transform: translateZ(0);
}
合成层优点
- 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
- 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
- 对于 transform 和 opacity 效果,不会触发 layout 和 paint
如果你已经把一个元素放到一个新的合成层里,那么可以使用 Chrome 来确认这么做是否真的改进了渲染性能。别盲目提升合成层,一定要分析其实际性能表现。
合成层管理
在内存资源有限的设备上,合成层带来的性能改善,可能远远赶不上过多合成层开销给页面性能带来的负面影响。
不正确使用硬件加速的后果:https://static.chenng.cn/composite-layers/index.html
使用 3D 硬件加速提升动画性能时,最好给元素增加一个 z-index 属性,人为干扰复合层的排序,可以有效减少 chrome 创建不必要的复合层,提升渲染性能,移动端优化效果尤为明显。
如果受限于视觉需要等因素,其他元素必须要覆盖在合成层之上,那应该尽量避免无法层压缩情况的出现。
大多数人都很喜欢使用 translateZ(0) 来进行所谓的硬件加速,以提升性能,但是性能优化并没有所谓的“银弹”,translateZ(0) 不是,本文列出的优化建议也不是。抛开了对页面的具体分析,任何的性能优化都是站不住脚的,盲目的使用一些优化措施,结果可能会适得其反。因此切实的去分析页面的实际性能表现,不断的改进测试,才是正确的优化途径。
文章参考: