浏览器渲染的合成层是什么

368 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情

核心描述

个人理解渲染合成层,其实是通过一些隐形或显形的设置,触发浏览器的渲染前的优化机制,从而提高整个页面的渲染性能。

  • 什么是渲染合成层:

    • 合成就是将页面的各个部分分成多个层、单独光栅化(浏览器根据文档的结构、每个元素的样式、页面的几何形状和绘制顺序转换为屏幕上的像素的过程)它们并在合成器线程中合成为一个页面的技术。
    • 满足某些特殊条件的渲染层,会被浏览器自动提升为合成层。合成层拥有单独的 GraphicsLayer,而其他不是合成层的渲染层,则和其第一个拥有 GraphicsLayer 的父层共用一个。
  • 怎么触发合成层:

    • 显示触发
      • 具有 CSS3D 属性 CSS 透视效果
      • 包含的 RenderObject 节点表示的是使用硬件加速的视频解码技术的 HTML5video 元素
      • 包含的 RenderObject 节点包含使用了硬件加速的 Canvas2D 或 WebGL 技术
      • 使用 CSS 透明效果或 CSS 变形动画(使用 will-change 属性)
      • 使用了硬件加速的 CSS Filters 技术(有的文献中表示 filters 属性并没有提升为合成层的效果,推测只有一部分 filters 滤镜效果需要使用硬件加速,并非所有)
      • 使用了剪裁 Clip 或者反射 Reflection,并且它的后代中包含一个合成层
      • 拥有一个Z坐标比自己小的兄弟节点,且该节点是一个合成层。
    • 隐式触发
      • 一个或多个非合成元素应出现在堆叠顺序上的合成元素之上,会被提升为合成层。
  • 合成层的优缺点

    • 优点:
      • 合成层的位图,会交由 GPU 合成,比 CPU 处理要快得多;
      • 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层;
      • 元素提升为合成层后,transform 和 opacity 才不会触发 repaint,如果不是合成层,则其依然会触发 repaint。
    • 缺点:
      • 绘制的图层必须传输到 GPU,这些层的数量和大小达到一定量级后,可能会导致传输非常慢,进而导致一些低端和中端设备上出现闪烁;
      • 隐式合成容易产生过量的合成层,每个合成层都占用额外的内存,而内存是移动设备上的宝贵资源,过多使用内存可能会导致浏览器崩溃,让性能优化适得其反。
  • 什么是层压缩

    • 层隐式合成的例子,可能简单的重叠就会产生大量的合成层,这样会占用很多无辜的 CPU 和 内存资源,严重影响了页面的性能。这一点浏览器也考虑到了,因此就有了层压缩(Layer Squashing)的处理。
    • 浏览器的自动层压缩并不是万能的,有很多特定情况下,浏览器是无法进行层压缩的。比如 video 元素的渲染等。
  • 什么是层爆炸

    • 同合成层重叠也会使元素提升为合成层,虽然有浏览器的层压缩机制,但是也有很多无法进行压缩的情况。也就是说除了我们显式的声明的合成层,还可能由于重叠原因不经意间产生一些不在预期的合成层,极端一点可能会产生大量的额外合成层,出现层爆炸的现象。
    • 解决层爆炸的问题,最佳方案是打破 overlap 的条件,也就是说让其他元素不要和合成层元素重叠,譬如巧妙的使用 z-index 属性。
  • 如何查看渲染合成层(以 Chrome 为例:

4283411233-11ea431d4f7a4644_fix732.webp

知识拓展

  • 浏览器渲染流程:JavaScript 执行 -> Style 计算 -> Layout 布局 -> Paint 绘制 -> Composite 合成
    • JavaScript :一般来说,我们会使用 JavaScript 来实现一些视觉变化的效果。比如做一个动画或者往页面里添加一些 DOM 元素等。
    • Style 样式计算:根据 CSS 选择器,对每个 DOM 元素匹配对应的 CSS 样式。这一步结束之后,就确定了每个 DOM 元素上该应用什么样的 CSS 样式规则。
    • Layout 布局:确定了每个 DOM 元素的样式规则之后,这一步具体计算每个 DOM 元素最终在屏幕上显示的大小和位置。WEB 页面中元素的布局是相对的,因此一个元素的布局发生变化,会联动的引发其他元素的布局发生变化。比如 body 元素的宽度变化会影响到其子元素的宽度,其子元素的宽度变化也会继续对其孙子元素产生影响。因此对于浏览器来说,Layout 布局阶段是经常发生的。
    • Paint 绘制:本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个 DOM 元素所有的可视效果。一般来说,这个绘制过程是在多个层上完成的。
    • Composite 渲染层合成:页面中 DOM 元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。对于有位置重叠的元素页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常。
  • 图形层(GraphicsLayer)
    • GraphicsLayer 其实是一个负责生成最终准备呈现的内容图形的层模型,它拥有一个图形上下文(GraphicsContext),GraphicsContext 会负责输出该层的位图。存储在共享内存中的位图将作为纹理上传到 GPU,最后由 GPU 将多个位图进行合成,然后绘制到屏幕上,此时,我们的页面也就展现到了屏幕上。
    • GraphicsLayer 是一个重要的渲染载体和工具,但它并不直接处理渲染层,而是处理合成层。
  • 个人理解:很多优化技术,只有在遇到了,再去实践才是最佳实践。因为没有深入的理解和实践,盲目的引入,反而会引发一些不可预知的问题。尤其是当业务还没有达到需要优化的阶段,还是应该以业务为主。

参考资料

浏览知识共享许可协议

本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。