浏览器渲染机制

cenweilings@163.com Lv2

参考视频

  1. 浏览器渲染页面的流程
  2. 【干货】浏览器是如何运作的?

浏览器渲染机制:从 HTML 到像素的完整解析

渲染流水线概览

浏览器渲染流程

详细渲染阶段解析

1. 解析 HTML 构建 DOM 树

  • 过程
    • 字节 → 字符 → 令牌(token化) → 节点 → DOM 树
    • 遇到 <script> 标签会暂停解析,执行 JavaScript
  • 优化点
    • 使用 asyncdefer 属性异步加载脚本
    • 将脚本放在 body 底部

2. 解析 CSS 构建 CSSOM 树

  • 特点
    • CSS 是渲染阻塞资源
    • 选择器复杂度影响构建速度
  • 优化点
    • 精简 CSS 选择器复杂度
    • 使用媒体查询避免不必要的加载

3. 构建渲染树(Render Tree)

  • 组合过程
    • DOM + CSSOM = 渲染树
    • 只包含可见节点(排除 display: none 等元素)
  • 关键规则
    • CSS 层叠规则决定最终样式

4. 布局(Layout / Reflow)

  • 计算
    • 确定所有元素的几何位置和尺寸
    • 基于视口大小计算位置
  • 触发条件
    • 窗口大小调整
    • 元素位置/尺寸变化
    • 字体大小变化

5. 分层(Layer)

  • 分层原因
    • 实现高效动画和滚动
    • 独立处理不同层
  • 创建层条件
    • 3D 变换
    • 视频/Canvas 元素
    • 有动画的元素
    • will-change: transform 属性

6. 绘制(Paint)

  • 过程
    • 将渲染树转换为像素操作
    • 生成绘制指令列表
  • 特点
    • 最耗时的渲染阶段之一
    • 文本和边框绘制成本高

7. 光栅化(Rasterization)

  • 任务
    • 将绘制指令转换为位图
    • 在合成线程中执行
  • 优化
    • 分块光栅化(Tile-based)
    • GPU 加速

8. 合成显示(Compositing)

  • 过程
    • 合成器线程组合所有层
    • 通过 IPC 传递给浏览器进程
    • 最终显示在屏幕上
  • 优势
    • 避免完整重绘
    • 高效处理滚动和动画

关键渲染路径(Critical Rendering Path)

关键渲染路径(Critical Rendering Path)

回流与重绘

1. 回流(Reflow)

定义:当渲染树(Render Tree)中的一部分或全部因为元素的尺寸、布局、隐藏等改变而需要重新构建的过程称为回流。回流会导致子元素和后续元素重新计算布局,成本很高。
触发条件(常见):

  • 页面首次渲染(无法避免)
  • 浏览器窗口大小改变
  • 元素尺寸、位置、内容改变(如宽度、高度、内边距变化)
  • 添加或删除可见的DOM元素
  • 激活CSS伪类(如:hover
  • 查询某些属性或调用某些方法(如offsetWidthscrollTo()等)
    影响:回流会使浏览器重新计算所有受影响元素的几何属性,然后重新构建渲染树。

2. 重绘(Repaint)

定义:当元素的外观(如颜色、背景、边框等)发生改变,但不影响布局时,浏览器会重新绘制元素,这个过程称为重绘。重绘的成本通常小于回流。
触发条件

  • 颜色、背景色、边框颜色等样式改变
  • 文本方向修改
  • 阴影变化(但不影响布局)
  • visibility属性改变(注意:display: none会触发回流,而visibility: hidden只触发重绘)

关键区别:

特点 回流(Reflow) 重绘(Repaint)
触发原因 布局改变(几何属性) 外观改变(非几何属性)
性能影响 高(涉及子元素和后续元素重新布局) 低(只重新绘制,不重新计算布局)
依赖关系 必然引起重绘 不一定引起回流

渲染性能优化策略

1. 减少渲染阻塞

  • CSS
    • 内联关键 CSS
    • 使用媒体查询分割 CSS
    • 避免使用 @import
  • JavaScript
1
2
3
<!-- 推荐写法 -->
<script defer src="script.js"></script>
<script async src="analytics.js"></script>

2. 优化布局和重绘

  • 减少回流(Reflow)
    • 避免频繁读写布局属性(offsetTop 等)
    • 使用 CSS 类批量修改样式
    • 使用 position: absolute/fixed 脱离文档流
  • 减少重绘(Repaint)
    • 使用 transformopacity 实现动画
    • 使用 will-change 提示浏览器
    • 避免使用渐变和阴影等昂贵效果

3. 高效利用图层

  • 图层优化
1
2
3
4
.animate-element {
will-change: transform; /* 提前告知浏览器 */
transform: translateZ(0); /* 强制创建新层 */
}
  • 注意事项
    • 避免过多图层(内存开销)
    • 平衡图层数量和渲染性能

4. 虚拟滚动和列表优化

  • 大数据集处理
    • 实现虚拟滚动:只渲染可视区域元素
    • 使用内容分块加载
    • 懒加载非关键资源

5. 性能检测工具

  • Chrome DevTools
    • Performance 面板分析渲染瀑布流
    • Layers 面板查看图层结构
    • Rendering 面板检测重绘区域
  • API
1
2
3
4
5
// 获取布局性能数据
const perfEntries = performance.getEntriesByType("layout");
perfEntries.forEach(entry => {
console.log(`布局耗时: ${entry.duration}ms`);
});

现代浏览器渲染优化技术

1. 合成器线程(Compositor Thread)

  • 独立于主线程运行(浏览器渲染进程的主线程)
  • 处理滚动、动画等无需 JS 的操作
  • 直接操作已光栅化的图层

2. 时间切片(Time Slicing)

  • 将大型任务拆分为小任务
  • 通过 requestIdleCallback 实现
1
2
3
4
5
6
7
8
function processTask() {
// 执行小段任务

if (hasMoreWork) {
requestIdleCallback(processTask);
}
}
requestIdleCallback(processTask);

3. 增量渲染

  • 逐步显示部分渲染内容
  • 优先渲染视口内内容
  • 后台继续处理剩余内容

4. GPU 加速

  • 使用 CSS 硬件加速:
1
2
3
4
5
.accelerated {
transform: translate3d(0, 0, 0);
/* 或者 */
backface-visibility: hidden;
}
  • 将渲染工作转移到 GPU

渲染过程中的 JavaScript 交互

JS 执行对渲染的影响

  • 同步 JS
    • 阻塞 DOM 构建
    • 延迟页面渲染
  • 异步 JS
    • defer:HTML 解析完成后执行
    • async:下载完成后立即执行

事件循环与渲染协调

  • 处理模型
    1. 执行 JavaScript 任务
    2. 处理微任务队列
    3. 执行渲染步骤(可选)
    4. 处理宏任务队列
  • requestAnimationFrame
1
2
3
4
5
6
7
8
9
10
function update() {
// 在渲染前更新动画
element.style.transform = `translateX(${position}px)`;

position += 5;
if (position < 300) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);

最佳时机:在浏览器重绘前执行动画更新

移动端渲染的特殊考虑

触摸事件处理:

- 300ms 点击延迟问题
- 使用 `touch-action` 优化滚动
1
2
3
.scrollable {
touch-action: pan-y; /* 只允许垂直滚动 */
}

电池效率优化:

  • 减少不必要的动画
  • 使用 matchMedia 检测设备能力
1
2
3
4
const isLowPower = matchMedia("(prefers-reduced-motion: reduce)").matches;
if (isLowPower) {
// 简化动画效果
}

内存限制:

- 移动设备图层内存限制更严格
- 避免大型 Canvas 操作
- 及时释放不再使用的资源

未来趋势:WebGPU 和渲染新特性

  1. WebGPU
    • 下一代图形 API
    • 更直接的 GPU 访问
    • 适用于复杂 3D 和计算任务
  2. Houdini API
1
2
3
4
5
6
7
8
9
// 自定义绘制API示例
registerPaint('circle-ripple', class {
paint(ctx, size) {
ctx.fillStyle = 'rgba(255,0,0,0.5)';
ctx.beginPath();
ctx.arc(size.width/2, size.height/2, 50, 0, 2*Math.PI);
ctx.fill();
}
});
- 使开发者能介入渲染管线
- 创建高性能自定义渲染效果
  1. OffscreenCanvas
    • 在 Web Worker 中执行 Canvas 操作
    • 避免阻塞主线程
1
2
const offscreen = canvas.transferControlToOffscreen();
worker.postMessage({ canvas: offscreen }, [offscreen]);
  • Title: 浏览器渲染机制
  • Author: cenweilings@163.com
  • Created at : 2023-12-15 16:00:00
  • Updated at : 2025-09-14 14:56:58
  • Link: https://blog-git-main-cenweilings-projects.vercel.app/2023/12/15/浏览器渲染机制/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments