人人都会AI编程

18.1 关键渲染路径:HTML → DOM、CSS → CSSOM → 渲染树 → 布局 → 绘制 → 合成

更新时间:2026-07-11

浏览器从接收到 HTML 文档到最终将像素显示在屏幕上,会经历一系列严谨的步骤。这一整套流程被称为关键渲染路径(Critical Rendering Path)。理解这条路径,是优化页面首屏加载速度和交互流畅度的理论基础。下面我们一步步拆解。

18.1.1 从 HTML 到 DOM

浏览器通过网络接收到 HTML 字节数据后,并不会等待整个文档下载完成才开始工作。它采用增量式解析策略:一边下载,一边将字节流转换为字符,再通过词法分析和语法分析构建 DOM 树(Document Object Model)。

DOM 树是一个以 document 为根节点的树形结构,每个 HTML 标签对应一个元素节点,文本内容对应文本节点,注释也会被解析为注释节点。这一过程本质上是将“扁平”的标签文本转化为可编程访问的、具有层级关系的对象模型——正是后续 JavaScript 操作页面的入口。

注意两个容易误解的点

  • 构建 DOM 的过程中,遇到 CSS、JavaScript 等外部资源会暂时阻塞,后面会详细说明。
  • DOM 树不是渲染输出的最终形态,它只描述了文档的结构和内容,不包含任何视觉样式信息。

18.1.2 从 CSS 到 CSSOM

CSS 字节数据同样被下载、解析,最终生成 CSSOM 树(CSS Object Model)。与 DOM 不同,CSS 的解析不能完全增量进行——因为后面出现的规则可能覆盖或影响前面的规则,浏览器必须等到所有 CSS 都加载并解析完毕,才能确认最终生效的样式。

CSSOM 树记录了每一个 DOM 节点对应的、由层叠规则计算得出的最终样式(computed styles)。需要注意的是:

  • CSSOM 构建是阻塞渲染的:在 CSSOM 完成之前,浏览器不会进行任何绘制操作。这也意味着未加载完的样式表会推迟页面的视觉呈现。
  • 媒体查询(media 属性)可以标记某些样式表为非阻塞(仅在匹配时阻塞),这是常见的优化手段。

18.1.3 渲染树(Render Tree)的生成

DOM 树和 CSSOM 树构建完成后,浏览器将两者结合,生成渲染树。渲染树只包含真正需要显示的节点:

  • 不可见节点(如 <head> 内的元素、display: none 的元素)不会出现在渲染树中。
  • 伪元素(::before::after)虽然不在 DOM 中,但会在渲染树中创建对应节点。
  • 每个渲染树节点都携带了对应的 DOM 节点和计算后的 CSS 样式,明确了该节点将在页面上的几何形状和视觉表现

渲染树是随后布局和绘制阶段的输入,它是视觉输出的蓝图。

18.1.4 布局(Layout)

有了渲染树,浏览器就可以开始计算每个节点的确切尺寸和位置,这个过程称为布局(也叫回流,reflow)。

布局是一个自上而下、自左而右的递归过程:

  • 从根节点(通常对应 document 的视口)开始,根据 CSS 盒模型计算每个元素的宽高、内边距、边框、外边距,以及其在页面上的精确坐标。
  • 百分比、相对单位(em、rem、vw)会在布局阶段转化为绝对像素值。
  • 布局的计算结果保存在渲染树节点上,每个节点都拥有了自己的布局信息(即盒模型数据)。

布局的性能开销通常与页面中节点的数量和复杂度成正比。任何导致渲染树结构或节点几何属性改变的操作,都可能触发局部或全局的重新布局(回流)。

18.1.5 绘制(Paint)

布局完成后,浏览器进入绘制阶段,将每个节点的文本、颜色、边框、阴影、背景等视觉样式真正“画”出来。

绘制并不是一次性地给整个页面涂色,而是将页面分割成多个绘制层(layers),按特定顺序填充像素。你可以打开浏览器 DevTools 的 Layers 或 Rendering 面板看到这些层。绘制过程会生成一系列绘制指令,记录先画什么、后画什么、用什么颜色。

18.1.6 合成(Composite)

现代浏览器普遍采用分层合成机制。如果页面中的某些元素符合特定条件(如具有 CSS 3D 变换、will-change 属性、<video><canvas> 等),它们会被提升为独立的合成层

合成层的操作由 GPU 直接处理,极其高效。浏览器将各层的绘制结果最终合并为屏幕上的一幅画面:

  1. 各层先在内存中进行绘制,生成位图。
  2. 合成器线程将各层按正确的 Z 轴顺序叠加,应用变换、透明度等效果。
  3. 输出到屏幕。

合成的关键优势:如果某个元素只是改变 transformopacity,完全可以在合成器线程中处理,不需要触发布局和绘制,仅需重新合成。这就是为什么 CSS 动画应该优先使用 transformopacity——它们是最“便宜”的属性,不会引起主线程的昂贵开销。

18.1.7 渲染流程与阻塞行为总结

将上述步骤串联起来,关键渲染路径的完整链路为:

解析 HTML 构建 DOM → 下载并解析 CSS 构建 CSSOM → 合成渲染树 → 布局计算几何信息 → 绘制生成位图 → 合成层并显示

在这个过程中,有几种会阻塞或延迟渲染的情况需要格外留意:

  • CSS 阻塞渲染:未完成的 CSSOM 会阻塞渲染树生成及后续所有步骤。将关键 CSS 内联、非关键 CSS 延迟加载、合理拆分媒体查询可以降低阻塞影响。
  • JavaScript 阻塞解析:脚本会阻塞 DOM 构建(除非标记为 asyncdefer),因为脚本可能修改 DOM 甚至查询当前样式,浏览器必须暂停解析等待脚本执行完毕。这也是“脚本放底部”或使用 defer 建议的根源。
  • 渲染阻塞:渲染树生成前,浏览器不会渲染任何内容,因此减少关键资源数量和大小是首屏优化的核心。

18.1.8 实战优化思路

理解了关键渲染路径后,优化方向自然浮现:

  1. 减少关键资源数量:HTML、阻塞渲染的 CSS、阻塞解析的 JS 都是关键资源。尽量移除不必要的请求,将非关键 CSS 异步加载,脚本使用 deferasync
  2. 缩减关键资源大小:压缩 HTML、CSS、JS,使用 Tree Shaking 减少无用代码。
  3. 缩短关键路径长度:减少资源间的依赖链,比如内联关键 CSS 可以省去一次网络往返。
  4. 避免不必要的布局和绘制:批量修改 DOM、使用 class 替代表格直接操作样式、优先使用 transformopacity 做动画——这些都直接关联到 18.2 节将要深入的重排与重绘。

关键渲染路径是浏览器性能优化的根基知识。掌握它,你就能从“感觉哪里慢”升级为“精确知道瓶颈在哪一步”,对症下药。