问题?
- 页面上的元素发生位移一定会造成重排或者重绘吗?
Chrome 是如何将 DOM 转变成一个屏幕图像
- 获取 DOM 并将其分割为多个层
- 将每个层独立的绘制进位图中
- 将层作为纹理上传至 GPU
- 复合多个层来生成最终的屏幕图像。
Chrome渲染过程
-
JavaScript
:一般来说,我们会使用 JavaScript 来实现一些视觉变化的效果。比如做一个动画或者往页面里添加一些 DOM 元素等。 -
Style
:计算样式,这个过程是根据 CSS 选择器,对每个 DOM 元素匹配对应的 CSS 样式。这一步结束之后,就确定了每个 DOM 元素上该应用什么 CSS 样式规则。 -
Layout
:布局,上一步确定了每个 DOM 元素的样式规则,这一步就是具体计算每个 DOM 元素最终在屏幕上显示的大小和位置。web 页面中元素的布局是相对的,因此一个元素的布局发生变化,会联动地引发其他元素的布局发生变化。比如,<body>
元素的宽度的变化会影响其子元素的宽度,其子元素宽度的变化也会继续对其孙子元素产生影响。因此对于浏览器来说,布局过程是经常发生的。 -
Paint
:绘制,本质上就是填充像素的过程。包括绘制文字、颜色、图像、边框和阴影等,也就是一个 DOM 元素所有的可视效果。一般来说,这个绘制过程是在多个层上完成的。 -
Composite
:渲染层合并,由上一步可知,对页面中 DOM 元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。对于有位置重叠的元素的页面,这个过程尤其重要,因为一旦图层的合并顺序出错,将会导致元素显示异常。
渲染阶段性能优化
在渲染阶段,性能优化的手段:
- 减少页面重绘
- 减少页面重绘的范围
渲染阶段涉及的层(Layer)
-
GraphicsLayer(负责 RenderLayer 的子树)
- GraphicsLayer 是作为纹理Texture上传给 GPU 的
- demo1.html
-
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
本身,不会影响到其他的层 - 对于
transform
和opacity
效果,不会触发layout
和paint
合成层实际应用:动画
- demo3.html
- demo4.html
- demo5.html
- 打开
chrome >> ⋮ >> more tools >> task manager
,查看进程与内存
合成层实际应用:拖拽
为什么要有合成层
如果没有合成层,网页中将不会有流畅的动画,视频(Video)也无法正常播放
合成层是把双刃剑
渲染分为两步:绘制
和合成
。绘制(JS,Style,Layout,Paint)都是在CPU上完成的,合成是在GPU上。但是从CPU到GPU的转换是需要一些前置工作的。
- CPU将每个合成层绘制为单独的图像。
- 准备图层数据(大小,偏移,不透明度等)。
- 为动画准备着色器(如果适用)。
- 将数据发送到GPU。
层爆炸 Layer Explosion
- 当合成层过多时,会造成页面卡顿,用户体验大幅下降(GPU负载过高)
- demo6.html
层压缩 Layer Squashing
- 浏览器也考虑到可能会造成Layer Explosion的情况,因此浏览器会对某些非直接原因创建的合成层进行合并。
- demo6.html
关于rendering面板的使用
- Emulate CSS media type - print & screen
- Emulate CSS media feature prefers-color-scheme
- Emulate vision deficiencies
- Emulate Auto Dark mode
回到开头
- 页面上的元素发生位移一定会造成重排或者重绘吗?
- 但是...
参考文档
- The Chromium Projects design docs
- Chrome DevTools
- Chrome Web DEV
- Layers
- CSS GPU Animation: Doing It Right
- Rendering
- Texture
评论