渲染流程
约 1441 字大约 5 分钟
2025-07-10
导航被提交后就会进入到渲染流程。通常,在编写好 HTML、CSS、JS 等文件,经过浏览器 渲染模块 的处理后就会展现出来,整个过程常被称为渲染流水线(Rendering Pipeline)

| 阶段 | 输入 | 输出 |
|---|---|---|
| DOM 构建 | HTML | DOM Tree |
| 样式计算 | CSS + DOM | Computed Style |
| 布局(Layout) | DOM + Style | Layout Tree(几何信息) |
| 分层(Layer) | Layout Tree | Layer Tree |
| 绘制(Paint) | Layer Tree | Display List |
| 光栅化(Raster) | Display List | 位图 Tiles |
| 合成(Composite) | 位图 Tiles | 最终帧 |
构建 DOM 树
浏览器先把 HTML 文本解析成结构化树,便于后续处理

样式计算
styleSheets 转换
渲染引擎接收到 CSS 时会执行转换操作,将 CSS 转换为浏览器可以理解的 styleSheets 结构,该结构同时具备了查询和修改功能,为样式操作提供了基础
可以在控制台中输入
document.styleSheets查看
styleSheets 结构 标准化
当转换为 styleSheets 后,接下来就是 对其属性值的标准化操作,需要将不易被渲染引擎理解的 2em,blue 等属性转换为使其容易理解的、标准化的计算值

样式标准化 样式计算
接下来就是需要计算 DOM 节点中每个节点的样式属性,其目的是为了计算出 DOM 节点中每个元素的具体样式,并且在该过程中需要遵守 CSS 的 继承 和 样式层叠 两个规则
最终输出的内容是每个 DOM 节点的样式,并被保存在 ComputedStyle 结构内
图示

样式计算
布局(Layout)
虽然通过前两个子阶段已经得到了 DOM 树和 DOM 树中每个节点的样式,但还不足以展示页面,因为 DOM 元素的集合位置信息还未知,因此 在该阶段就需要计算出 DOM 树中可见元素的几何位置,这个过程就成为布局,此阶段段需要完成两个任务:创建布局树 和 布局计算
创建布局树
在 DOM 树中,有一些是使用了 display: none 属性的元素。因此在显示之前需要额外构建一科只包含可见元素的布局树,为了构建布局树浏览器会遍历 DOM 树中所有节点,忽略不可见的节点,把可见节点加到布局树中

布局计算
生成布局树后,就需要计算布局树节点的坐标位置,布局计算过程非常复杂,只需知道:在执行布局操作时,会把布局运算的结果重新写回布局树中,所以布局树即是输入内容也是输出内容
分层
即使已经有了每个元素的具体位置信息,页面现在依然是无法被绘制的。因为页面中可能会有许多复杂效果,例如 3D 变化、页面滚动或使用 z-index 做 z 轴排序等。而为了更方便的实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)
浏览器的页面实际被分层了许多图层,这些图层叠加后合成了最终的页面
图示

不会称为独立图层的情况
- 层叠上下文(如
transform、opacity、特定定位) - 裁剪(clip)和滚动容器
- 合成优化策略命中
绘制
完成图层树的构建后,渲染引擎会对图层中的每个图层进行绘制。渲染引擎会将每个图层的绘制拆分成许多绘制指令,然后再将指令按照顺序组成一个待绘制列表
图示

栅格化
通常,一个页面可能很大,但用户缺只能看到视口的一小部分,所以在这种情况下绘制出所有图层内容的话,产生的开销也是很大的。基于该原因,合成线程会将图层划分为 图块(tile),这些图块的大小通常是 256 x 256 或者 512 x 512,然后合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图
图示

图块
图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的。通常,栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中
图示

合成与显示
一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令 ——“DrawQuad”,然后根据该指令提交给浏览器进程,然后通过浏览器进程中的 viz 组件来接收合成线程发过来的 DrawQuad 命令,在根据该命令将页面内容绘制到内存中,最后再将内存显示在屏幕上
