浏览器渲染过程
理解浏览器如何将 HTML、CSS 和 JavaScript 转换为屏幕上的像素,是优化网页性能的关键。本文将深入剖析浏览器渲染的完整流程。
核心概念:DOM 树 vs 渲染树
浏览器的渲染过程是「完整解析 DOM 树,但有选择地渲染可见内容」。理解这两者的区别至关重要。
💡 核心理念
浏览器「心里有数」(完整 DOM 树),但「只做有用的」(选择性渲染可见内容)。
对比说明
| 特性 | DOM 树 | 渲染树 |
|---|---|---|
| 包含内容 | 所有 HTML 元素,包括 display:none、script、link、meta 等 | 只包含可见元素 |
| 目的 | JS 操作和动态变化的基础 | 布局和绘制的基础 |
| 生成时机 | HTML 解析时立即构建 | DOM 树 + CSSOM 树结合后生成 |
| 结构 | 与 HTML 结构完全对应 | 包含样式信息,与 DOM 不同 |
渲染流程总览
浏览器将 HTML/CSS/JS 转换为屏幕像素的完整流程包含以下步骤:
1. HTML 解析 → DOM 树
↓
2. CSS 解析 → CSSOM 树
↓
3. DOM + CSSOM → 渲染树
↓
4. 布局(Layout)
↓
5. 绘制(Paint)
↓
6. 合成(Composite)→ 屏幕
哪些元素被排除在渲染树之外?
| 排除类型 | 说明 | 示例 | 影响 |
|---|---|---|---|
| display: none | 完全从渲染树移除 | <div style="display:none"> |
不占空间,触发重排 |
| 非视觉元素 | 没有视觉表现 | <script>, <link>, <meta> |
不影响渲染 |
| visibility: hidden | 在渲染树中,但不绘制 | <div style="visibility:hidden"> |
占空间,不触发重排 |
| 完全遮挡的元素 | 可能被优化跳过绘制 | 被不透明元素覆盖 | 仍在渲染树,布局需要 |
渲染树可视化示例
HTML 结构:
<div class="container">
<div class="visible">我是可见的</div>
<div class="hidden" style="display: none;">我是 display: none 的</div>
<div class="invisible" style="visibility: hidden;">我是 visibility: hidden 的</div>
<script>console.log('我是 script')</script>
</div>
DOM 树(完整):
div.container
div.visible
div.hidden
div.invisible
script
渲染树(选择性):
div.container
div.visible
div.invisible
div.hidden
script
渲染三阶段:布局 → 绘制 → 合成
📐
布局(Layout)
计算渲染树中元素的几何信息(宽、高、位置)
🎨
绘制(Paint)
将元素绘制成像素,填充颜色、文本、边框等
🖥️
合成(Composite)
将多个层合成到屏幕上,利用 GPU 加速
各阶段优化策略
| 阶段 | 优化策略 | 说明 |
|---|---|---|
| 布局 | 增量布局 | 只重新布局变化的元素 |
| 视口外延迟布局 | 滚动到附近时再计算 | |
| 绘制 | 分层绘制 | 每层独立绘制,最后合成 |
| 增量绘制 | 只重绘变化的层 | |
| 合成 | GPU 加速 | 利用 GPU 处理层合成 |
| 跳过遮挡层 | 被完全遮挡的层跳过合成 |
浏览器优化层次图
🚀 合成层(GPU 加速)
最快
🎨 绘制层(分层绘制)
快
📐 布局层(增量布局)
中
🌳 渲染树构建
基础
💡 性能优化建议
使用 transform 和 opacity 动画可触发 GPU 加速,避免重排重绘。
display: none vs visibility: hidden
| 特性 | display: none | visibility: hidden |
|---|---|---|
| 渲染树 | ❌ 移除 | ✅ 保留 |
| 占空间 | ❌ 不占 | ✅ 占空间 |
| 触发重排 | ✅ 是 | ❌ 否 |
| 触发重绘 | ✅ 是 | ✅ 是 |
| 可继承 | ❌ 否(子元素也不显示) | ✅ 是(子元素可覆盖) |
| 屏幕阅读器 | ❌ 不读 | ❌ 不读 |
触发 GPU 加速的 CSS 属性
使用以下属性可触发 GPU 加速,提升动画性能:
| 属性 | 说明 | 性能 |
|---|---|---|
transform |
2D/3D 变换 | ⭐⭐⭐⭐⭐ |
opacity |
透明度变化 | ⭐⭐⭐⭐⭐ |
filter |
滤镜效果 | ⭐⭐⭐⭐ |
will-change |
提前告知浏览器 | ⭐⭐⭐⭐ |
content-visibility |
视口外跳过渲染 | ⭐⭐⭐⭐⭐ |
/* 优化动画示例 */
.animated-element {
/* 触发 GPU 加速 */
transform: translateZ(0);
will-change: transform, opacity;
/* 视口外跳过渲染(Chrome 85+)*/
content-visibility: auto;
contain-intrinsic-size: 300px;
}
总结
📄 DOM 树:完整解析,一个都不能少
↓
🎨 渲染树:有选择,只包含可见元素
↓
📐 布局/绘制/合成:进一步优化,只处理可见内容
↓
🖥️ 利用增量更新、分层绘制、GPU 加速提升性能
🎯 关键要点
浏览器 「心里有数」(完整 DOM 树),但「只做有用的」(选择性渲染可见内容)。