浏览器渲染原理浅析

2026-06-22 · 6 阅读 · 370字
HTML性能优化

浏览器渲染原理浅析

从 URL 到页面

用户在地址栏输入 URL 后,浏览器经历以下过程:

  1. DNS 解析:将域名解析为 IP 地址
  2. TCP 连接:三次握手建立连接(HTTPS 额外有 TLS 握手)
  3. 发送 HTTP 请求:请求 HTML 文档
  4. 服务器响应:返回 HTML
  5. 浏览器解析渲染:将 HTML/CSS/JS 转换为像素

浏览器架构

主要进程

  • 浏览器进程:管理标签页、地址栏、书签等
  • 渲染进程(Chrome 中每个标签页独立):负责 HTML、CSS、JS 的解析和渲染
  • GPU 进程:处理 GPU 任务,加速渲染
  • 网络进程:处理网络请求
  • 插件进程:管理插件

渲染进程内部线程

  • 主线程:解析 HTML/CSS、执行 JS、计算样式、布局、绘制
  • 合成线程:将图层合成,处理滚动、动画
  • 光栅化线程:将图层转换为位图

关键渲染路径

第一步:解析 HTML → DOM 树

浏览器从网络进程接收 HTML 数据,逐步解析:

HTML 字节 → 字符 → 令牌(Token)→ 节点(Node)→ DOM 树
<html>
  <body>
    <h1>Hello</h1>
    <p>World</p>
  </body>
</html>

解析为 DOM 树:

Document
 └── html
      └── body
           ├── h1
           │    └── "Hello"
           └── p
                └── "World"

注意:遇到 <script> 标签会暂停解析,直到脚本下载并执行完毕。将脚本放在底部或使用 defer / async 可避免阻塞。

第二步:解析 CSS → CSSOM 树

CSS 字节 → 字符 → 令牌 → 节点 → CSSOM 树

body { font-size: 16px; }
h1 { color: blue; }

CSSOM 树与 DOM 树类似,但包含层叠样式信息。CSS 解析不会阻塞 HTML 解析,但会阻塞渲染(因为需要完整的 CSSOM 才能渲染)。

第三步:合并 → Render 树

DOM 树 + CSSOM 树 → Render 树

Render 树只包含可见元素(display: none 的元素不包含,但 visibility: hidden 的元素包含)。

Render 树
 ├── body { font-size: 16px; }
 ├── h1 { color: blue; font-size: 16px; }
 │    └── text "Hello"
 └── p { font-size: 16px; }
      └── text "World"

第四步:布局(Layout)

计算每个可见元素在视口中的位置和大小。从根节点开始递归计算:

  • 盒模型尺寸(width、height、padding、border、margin)
  • 位置(根据定位方式、浮动、flex、grid 等计算)

第五步:绘制(Paint)

将每个元素绘制到多个图层上。绘制顺序:

  1. 背景颜色/背景图片
  2. 边框
  3. 子元素
  4. 轮廓

第六步:合成(Composite)

图层合成到屏幕上。合成是 GPU 加速的关键步骤,只有 transformopacity 的变化可以在合成阶段完成,不触发布局和绘制。

重排与重绘

重排(Reflow / Layout)

当改变影响布局的属性时触发:

  • 尺寸:width、height、padding、border
  • 位置:top、left、margin、position
  • 内容变化:font-size、text 变化
  • DOM 增加/删除

代价最高,需要重新进行布局、绘制和合成。

重绘(Repaint)

当改变外观但不影响布局时触发:

  • color、background-color、visibility
  • outline、box-shadow(不影响布局时)

代价中等,跳过布局阶段。

仅合成(Composite-only)

最佳的动画性能:

  • transform: translate
  • transform: scale
  • opacity

代价最低,仅合成线程处理。

性能优化建议

减少重排

// 批量修改样式(避免逐条修改)
// 不推荐
element.style.width = '100px';
element.style.height = '100px';

// 推荐:使用 class
element.classList.add('new-style');

// 离线操作
const fragment = document.createDocumentFragment();
// 在 fragment 上操作...
document.body.appendChild(fragment);

// 使用 transform 替代 top/left
// 不推荐
element.style.top = '100px';

// 推荐
element.style.transform = 'translateY(100px)';

避免强制同步布局

// 错误:先读后写再读,触发强制同步布局
element.style.width = '100px';      // 写
const w = element.offsetWidth;      // 读 → 强制同步布局
element.style.height = w + 'px';    // 写

// 正确:读写分离
element.style.width = '100px';      // 写
element.style.height = '100px';     // 写
const w = element.offsetWidth;      // 读

总结

理解浏览器渲染原理是写出高性能前端代码的基础。核心要点是:尽量减少重排和重绘,使用合成友好的属性(transform、opacity)做动画,合理使用 will-change,读写 DOM 操作时注意批量处理。