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

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

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

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

什么是合成层?

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

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

img

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

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

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

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

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

提升为合成层的属性

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

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

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

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

合成层的好处和问题

合成层开启的好处

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

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

  • 对于 transform opacity效果,不会触发 layoutpaint

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

  • 如果我们把所有渲染工作都交给 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日
许可协议