浏览器渲染之什么是合成层?

居中为什么要使用 transform , 为什么不使用 margin Left/Top ?

在我们日常开发中经常会实现一些动画,有时候我们可能会选择改变 top/left 去实现,那么这个节点的渲染会发生在普通文档流中。该属性的变化会导致重排(reflow/relayout)

而使用 transform 和 opacity 实现动画能够让节点被放置到一个独立合成层中进行渲染绘制,动画不会影响其他图层,并且 GPU渲染相比 CPU 能够更快,这会让你的动画变的更加流畅

什么是合成层?

在讨论合成层之前我们先简单了解一下浏览器渲染,浏览器常见的渲染引擎有 Webkit/Gecko 等,他们的主要渲染流程基本相同

讨论一下 WebKit 简化的渲染流程。

img

  1. 浏览器下载并解析 HTML。
  2. 处理 CSS 构建 CSSOM 树,生成 DOM 树。
  3. DOM 与 CSSOM 合并成一个 Render 树。
  4. 有了 Render Tree,浏览器可以知道各个节点的 CSS 定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置,生成一个足够大的画布来容纳所有元素。
  5. 根据浏览器提供各层的信息合成图层,显示到屏幕上。

合成层就出现在最后一步流程中,这些合成图层中一些特殊的图层被认为是合成层(Compositing Layers)

首先合成就是将页面的各个部分分成多个层、单独光栅化它们并在合成器线程中合成为一个页面的技术。

光栅化 : 浏览器根据文档的结构、每个元素的样式、页面的几何形状和绘制顺序转换为屏幕上的像素的过程

  • 一般来说,拥有一些特定属性的渲染层,会被浏览器自动提升为合成层。
  • 合成层拥有单独的图层(GraphicsLayer),和其他图层之间无不影响。
  • 而其它不是合成层的渲染层,则和第一个拥有图层的父层共用一个,也就是普通文档流中的内容

提升为合成层的属性

我们看一些常见的提升为合成层的属性。

  • 设置 transform: translateZ(0),注意它必须是 translateZ,因为它使用 GPU来计算 perspective distortion(透视失真)。perspective 在 3D设计中是一个重要的属性。如果你使用 translateX 或 translateY,元素将会被绘制在普通文档流中
  • backface-visibility: hidden : 指定当元素背面朝向观察者时是否可见
  • transform / opacity
  • video、canvas、iframe 等元素。
  • will-change : 告诉浏览器该元素会有哪些变化,这样浏览器可以提前做好对应的优化准备工作。
    • 当该属性的值为 opacity、transform、top、left、bottom、right 时。

隐式合成就是特定场景下,存在会被默认提升为合成层的情况。

  • 一个或多个非合成元素应出现在堆叠顺序上 (z-index) 的合成元素之上,会被提升为合成层。

合成层的好处和问题

合成层开启的好处

  • 开启硬件加速,合成层的位图会交由 GPU合成,相比 CPU 处理要快。

  • 合成层发生 repaint的时候,不会影响其他图层。

  • 对于 transform 和 opacity效果,不会触发 layout和 paint。

当然合成层也存在一些问题:

  • 如果我们把所有渲染工作都交给 GPU,在现有的优化下,它会导致渲染内存占用比大幅度提升,反而出现负面的效果。
  • 另外隐式合成容易产生大量我们意料之外的合成层,过大的内存占用,会让页面变的卡顿,性能优化适得其反。

谨慎使用 will-change

除非你的元素的真的存在某个属性马上会发生变化,例如 transform,你可以使用 will-change: transform 告知浏览器,根据您打算更改的元素,浏览器可能可以预先安排,元素的改变和渲染速度都会变得更快。

这些属性可能会给你带来一些副作用

但需要注意的是,不要创建太多的渲染层。因为每创建一个新的渲染层,就意味着新的内存分配和更复杂的层的管理。

如果你已经把一个元素放到一个新的合成层里,那么可以使用 Timeline 来确认这么做是否真的改进了渲染性能。别盲目提升合成层,一定要分析其实际性能表现。

其实从性能方面考虑,最理想的渲染流水线是没有布局和绘制环节的,只需要做合成层的合并即可:

img

为了实现上述效果,就需要只使用那些仅触发 Composite 的属性。目前,只有两个属性是满足这个条件的:transforms 和 opacity。

合理管理合成层:

大多数人都很喜欢使用 translateZ(0) 来进行所谓的硬件加速,以提升性能

但是性能优化并没有所谓的”银弹” (可解决复杂问题的简单方案),translateZ(0) 不是,本文列出的优化建议也不是。

抛开了对页面的具体分析,任何的性能优化都是站不住脚的,盲目的使用一些优化措施,结果可能会适得其反。

  • 创建一个新的合成层并不是免费的,它得消耗额外的内存和管理资源。实际上,在内存资源有限的设备上,合成层带来的性能改善,可能远远赶不上过多合成层开销给页面性能带来的负面影响。因此切实的去分析页面的实际性能表现,不断的改进测试,才是正确的优化途径。

img


浏览器渲染之什么是合成层?
http://example.com/2023/10/26/CSS合成层/
作者
weirdo
发布于
2023年10月26日
更新于
2023年10月26日
许可协议