页面上的元素发生位移一定会造成重排或者重绘吗?

页面上的元素发生位移一定会造成重排或者重绘吗?

问题?

  • 页面上的元素发生位移一定会造成重排或者重绘吗?

Chrome 是如何将 DOM 转变成一个屏幕图像

  1. 获取 DOM 并将其分割为多个层
  2. 将每个层独立的绘制进位图中
  3. 将层作为纹理上传至 GPU
  4. 复合多个层来生成最终的屏幕图像。

Chrome渲染过程

browser-dom-render


  • JavaScript:一般来说,我们会使用 JavaScript 来实现一些视觉变化的效果。比如做一个动画或者往页面里添加一些 DOM 元素等。

  • Style:计算样式,这个过程是根据 CSS 选择器,对每个 DOM 元素匹配对应的 CSS 样式。这一步结束之后,就确定了每个 DOM 元素上该应用什么 CSS 样式规则。

  • Layout:布局,上一步确定了每个 DOM 元素的样式规则,这一步就是具体计算每个 DOM 元素最终在屏幕上显示的大小和位置。web 页面中元素的布局是相对的,因此一个元素的布局发生变化,会联动地引发其他元素的布局发生变化。比如,<body> 元素的宽度的变化会影响其子元素的宽度,其子元素宽度的变化也会继续对其孙子元素产生影响。因此对于浏览器来说,布局过程是经常发生的。

  • Paint:绘制,本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个 DOM 元素所有的可视效果。一般来说,这个绘制过程是在多个层上完成的。

  • Composite:渲染层合并,由上一步可知,对页面中 DOM 元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常。


渲染阶段性能优化

在渲染阶段,性能优化的手段:

  • 减少页面重绘
  • 减少页面重绘的范围

渲染阶段涉及的层(Layer)

  • GraphicsLayer(负责 RenderLayer 的子树)

  • Compositing Layers

  • 以下示例使用Chrome 96.0.4664.45进行展示


什么是图形层 (GraphicsLayer)

GraphicsLayer 其实是一个负责生成最终准备呈现的内容图形的层模型,他拥有一个图形上下文(GraphicsContext),GraphicsContext会负责输出该层的位图。存储在共享内存中的位图将作为纹理上传到 GPU 中,最后由 GPU 将多个位图进行合成,然后 draw 到屏幕上,此时,我们的页面也就展现到了屏幕上。


什么又是合成层 (Compositing Layers)

某些特殊的渲染层会被认为是合成层(Compositing Layers),合成层拥有单独的 GraphicsLayer,而其他不是合成层的渲染层,则和其第一个拥有 GraphicsLayer 父层公用一个。


合成层创建标准

  • 3D 或透视变换(perspective transform) CSS 属性
  • 使用加速视频解码的 <video> 元素
  • 拥有 3D (WebGL) 上下文或加速的 2D 上下文的 <canvas> 元素
  • 混合插件(如 Flash)

(接上页)

  • 对自己的 opacity 做 CSS 动画或使用一个动画变换的元素
  • 拥有加速 CSS 过滤器的元素
  • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
  • 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)

实际可用的代码

*{
    transform: translateZ(0);
    will-change: transform;
    will-change: opacity;
    backface-visibility: hidden;
}

合成层带来的好处

  • 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
  • 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
  • 对于 transformopacity 效果,不会触发 layoutpaint

合成层实际应用:动画


合成层实际应用:拖拽


为什么要有合成层

如果没有合成层,网页中将不会有流畅的动画,视频(Video)也无法正常播放


合成层是把双刃剑

渲染分为两步:绘制合成。绘制(JS,Style,Layout,Paint)都是在CPU上完成的,合成是在GPU上。但是从CPU到GPU的转换是需要一些前置工作的。

  • CPU将每个合成层绘制为单独的图像。
  • 准备图层数据(大小,偏移,不透明度等)。
  • 为动画准备着色器(如果适用)。
  • 将数据发送到GPU。

层爆炸 Layer Explosion

  • 当合成层过多时,会造成页面卡顿,用户体验大幅下降(GPU负载过高)
  • demo6.html

层压缩 Layer Squashing

  • 浏览器也考虑到可能会造成Layer Explosion的情况,因此浏览器会对某些非直接原因创建的合成层进行合并。
  • demo6.html

关于rendering面板的使用


回到开头

  • 页面上的元素发生位移一定会造成重排或者重绘吗?
  • 但是...

参考文档


风清洋

风清洋

保持原动力,迎接每一天

评论