Skip to content

浏览器渲染原理

目录


浏览器渲染页面的完整流程如下:

  1. 解析 HTML 构建 DOM 树
  2. 解析 CSS 构建 CSSOM 树
  3. 合并 DOM 和 CSSOM 构建渲染树
  4. 布局 计算元素位置和尺寸
  5. 绘制 将元素像素化
  6. 合成 将各层合并显示

2. DOM 构建过程

2.1 HTML 解析

HTML 解析器将 HTML 字节流转换为 DOM 树的过程:

  1. 字节解码:将网络接收的字节数据解码为字符
  2. 标记化(Tokenization):将字符流解析为标记(开始标签、结束标签、文本等)
  3. 树构建:根据标记构建 DOM 树

示例:HTML 解析过程

html
<!DOCTYPE html>
<html>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

解析器会生成以下标记:

  • DOCTYPE
  • StartTag: html
  • StartTag: body
  • StartTag: h1
  • Characters: Hello World
  • EndTag: h1
  • EndTag: body
  • EndTag: html

2.2 DOM 树生成

DOM(Document Object Model)树是 HTML 文档的内存表示,每个 HTML 元素对应一个 DOM 节点。

DOM 树特点:

  • 根节点是 document
  • 父子关系反映 HTML 嵌套结构
  • 包含所有 HTML 元素,包括不可见元素(如 <script><meta>
  • 不包含 CSS 样式信息

3. CSSOM 构建过程

3.1 CSS 解析

CSS 解析过程与 HTML 类似:

  1. 字节解码:将 CSS 字节流解码为字符
  2. 标记化:识别选择器、属性、值等
  3. 规则构建:构建 CSS 规则对象

示例:CSS 解析

css
body {
  font-size: 16px;
  color: #333;
}

h1 {
  font-weight: bold;
}

解析后生成两条 CSS 规则,每条规则包含选择器和声明块。

3.2 CSSOM 树生成

CSSOM(CSS Object Model)树是 CSS 样式的内存表示。

CSSOM 树特点:

  • 树形结构,继承关系反映 CSS 继承规则
  • 包含所有样式规则
  • 计算最终样式时需要考虑优先级(特异性)、继承和层叠

样式计算过程

  1. 收集规则:收集所有适用于元素的 CSS 规则
  2. 计算特异性:确定规则优先级
  3. 应用层叠:按优先级覆盖样式
  4. 继承:应用父元素继承的样式
  5. 默认值:填充未指定的默认值

4. 渲染树(Render Tree)构建

渲染树由 DOM 树和 CSSOM 树合并生成,只包含需要渲染的元素。

构建过程

  1. 遍历 DOM 树:从根节点开始遍历每个可见节点
  2. 过滤不可见节点
    • 排除 display: none 的元素
    • 排除 <script><meta> 等不可见元素
  3. 匹配样式:为每个可见节点匹配对应的 CSSOM 规则
  4. 创建渲染对象:生成 RenderObject 节点

渲染树 vs DOM 树

特性DOM 树渲染树
包含内容所有 HTML 元素仅可见元素
样式信息
用途JS 操作、语义渲染显示

5. 布局(Layout/Reflow)

布局阶段计算渲染树中每个节点的几何信息(位置和尺寸)。

布局过程

  1. 从根节点开始:从 <html> 根元素开始递归计算
  2. 盒模型计算:根据 CSS 盒模型计算宽高、边距、边框、填充
  3. 定位计算:确定元素在视口中的具体位置
  4. 流式布局:根据文档流排列元素

触发重排(Reflow)的操作

  • 添加/删除 DOM 元素
  • 元素位置变化
  • 元素尺寸变化(宽高、边距、边框等)
  • 内容变化(文本、图片尺寸)
  • 浏览器窗口大小变化
  • 获取某些属性(offsetWidth、offsetHeight、clientWidth、clientHeight、scrollTop 等)

6. 绘制(Paint)

绘制阶段将渲染树节点转换为屏幕上的像素。

绘制过程

  1. 分层绘制:将渲染树分为多个图层
  2. 填充像素:为每个图层绘制像素(颜色、图片、阴影等)
  3. 记录绘制命令:保存绘制操作的指令列表

绘制顺序(Stacking Context)

  1. 背景和边框
  2. 负 z-index 的子元素
  3. 常规流中的块级元素
  4. 浮动元素
  5. 常规流中的行内元素
  6. 正 z-index 的子元素

触发重绘(Repaint)的操作

  • 颜色变化
  • 背景变化
  • 阴影变化
  • 透明度变化(opacity)
  • visibility 变化

注意:重绘不一定触发重排,但重排一定触发重绘。


7. 合成(Composite)

合成阶段将绘制好的图层合并为最终的屏幕图像。

合成过程

  1. 图层排序:按 z-index 顺序排列图层
  2. 图层合成:将多个图层合并为一个最终图像
  3. 显示到屏幕:将最终图像显示在屏幕上

硬件加速

现代浏览器使用 GPU 进行合成,支持硬件加速的属性:

  • transform
  • opacity
  • filter
  • will-change

这些属性的变化不会触发重排和重绘,只会触发合成,性能最优。


8. 关键渲染路径优化

8.1 优化 DOM

  • 减少 DOM 节点数量
  • 避免深层嵌套
  • 使用语义化 HTML

8.2 优化 CSS

  • 关键 CSS 内联:将首屏所需 CSS 内联到 HTML 中
  • 延迟加载非关键 CSS:使用 media 属性或 JavaScript 异步加载
  • 简化选择器:避免过于复杂的 CSS 选择器
  • 减少 CSS 规则数量

8.3 优化 JavaScript

  • 异步加载脚本:使用 asyncdefer
  • 避免阻塞渲染的 JS:将脚本放在 </body>
  • 减少 DOM 操作:批量操作 DOM
  • 避免强制同步布局:避免在修改样式后立即读取布局属性

8.4 优化渲染性能

  • 减少重排和重绘:使用 transformopacity 替代 top/left/width/height
  • 使用 GPU 加速:合理使用 will-changetransform
  • 避免频繁的布局抖动:不要在循环中读取布局属性
  • 使用 requestAnimationFrame:将视觉变化放在 requestAnimationFrame 中执行

8.5 使用开发者工具

  • Performance 面板:记录和分析渲染性能
  • Layers 面板:查看图层分层情况
  • Rendering 面板:开启 Paint flashing、Layer borders 等调试选项

总结

浏览器渲染管道是一个复杂的过程,理解每个阶段的工作原理对于优化网页性能至关重要。通过优化关键渲染路径,可以显著提升页面加载速度和用户体验。

基于 VitePress 的本地知识库