浏览器渲染 首屏优化 性能优化
浏览器渲染就是把网页代码(HTML、CSS、JS、图片等)变成用户眼中看到的“可视页面”的过程
HTML 文本↓
1. 解析 HTML,构建 DOM 树↓
2. 解析 CSS,构建 CSSOM 树↓
3. 合并 DOM + CSSOM,生成 Render Tree(渲染树)↓
4. Layout(布局计算)↓
5. Paint(像素填充)↓
6. Composite(图层合成)
1. 构建 DOM 树(Document Object Model)
- 浏览器主线程解析 HTML
- 每一个标签节点都会被转换为一个 JS 对象(DOM 节点)
- 忽略 script、style 标签的 CSS(先不执行 JS 和样式
<body><div>Hello</div>
</body>
会变成:
Document
└── body└── div
2. 构建 CSSOM 树(CSS Object Model)
- 浏览器解析
div {color: red;
}
CSSOM 是类似这样的结构:
StyleSheet
└── Rule: div { color: red; }
生成渲染树(Render Tree)
- DOM + CSSOM 合并,生成一棵 “Render Tree”
- 不包括 display: none 的元素
- 每个可见节点会变成一个 “渲染对象”(RenderObject)
- 🧠 渲染树是“只包含可视化元素”的 DOM + CSS 组合体
4. Layout(布局阶段
也叫 Reflow(回流)计算每个渲染对象的具体位置、大小(几何信息)涉及布局模型(Block、Flex、Grid等)输出的是每个元素的:坐标、宽高、边距、盒模型等信息
5. Paint(绘制阶段)
也叫 重绘(Repaint)把每个节点的视觉样式(颜色、文字、边框、阴影等)画到屏幕的图层中形成一个或多个位图(Bitmap)注意:绘制是按图层进行的
6. Composite(合成阶段)
多个图层合成一张页面最终画面使用 GPU 加速合成(硬件加速)对于复杂动画、transform、position: fixed 等会被放入独立图层
示意图(流程图)
HTML + CSS + JS↓
【DOM】 ← HTML Parser
【CSSOM】 ← CSS Parser↓
【Render Tree】↓
Layout(计算位置)↓
Paint(绘制位图)↓
Composite(合成图层)↓
【用户可见页面】
1. 网络请求(下载 HTML/CSS/JS/图片)
2. 构建 DOM 树(HTML → DOM)
3. 构建 CSSOM 树(CSS → CSSOM)
4. 构建 Render Tree(DOM + CSSOM)
5. 布局(Layout / Reflow)
6. 绘制(Paint)
7. 合成层 & 合成(Compositing)
8. 显示到屏幕
渲染相关的性能点
操作类型 | 影响 |
---|---|
改变 DOM 结构 | 触发 Reflow + Repaint |
改变样式(颜色) | 触发 Repaint |
改变 layout 样式(宽高、位置) | 触发 Reflow + Repaint |
改变 transform、opacity | 不触发 Reflow,仅触发 GPU 合成 |
Reflow vs Repaint
名称 | 含义 | 性能影响 |
---|---|---|
Reflow | 布局计算(改变大小/位置) | 🟥 非常消耗 |
Repaint | 样式重绘(颜色、字体变化) | 🟨 一般消耗 |
div.style.width = '100px'; // Reflow + Repaint
div.style.backgroundColor = 'red'; // 只 Repaint
浏览器帧率与渲染时机(重要)
浏览器渲染遵循 刷新率 60Hz(16.6ms 一帧):
JS 主线程 + 渲染引擎 合作完成每一帧
requestAnimationFrame
用于让代码在“下一帧绘制前”运行
requestAnimationFrame(() => {// 更新 DOM 的操作,保证在下一帧渲染前完成
});
一个复杂变化时的例子(动图)
div.style.transform = 'translateX(100px)';
// 👉 创建新图层 → GPU 加速 → 合成阶段处理
但如果你这样:
div.style.left = '100px';
// 👉 会触发回流 → 性能下降
总结一句话:
浏览器渲染过程是:DOM + CSSOM → Render Tree → Layout → Paint → Composite → 屏幕呈现。其中任何一步变化都会影响页面性能与流畅度。
什么是渲染管线(Rendering Pipeline)?
- 渲染管线是浏览器从接收网页代码(HTML/CSS/JS)到最终绘制在屏幕上的整个技术过程的专业称呼。它是浏览器内部的核心流程。
渲染管线的六大步骤
HTML/CSS/JS↓
1. 构建 DOM 树
2. 构建 CSSOM 树
3. 构建渲染树(Render Tree)
4. 布局(Layout / Reflow)
5. 绘制(Paint / Repaint)
6. 合成(Composite)↓
GPU 将图像显示在屏幕
渲染管线图示(直观理解)
HTML/CSS↓ JavaScript可能修改DOM
[DOM] + [CSSOM]↓
[Render Tree]↓
[Layout / 回流]↓
[Paint / 重绘]↓
[Composite / 合成]↓
[屏幕显示]
触发渲染管线的时机
操作 | 触发阶段 |
---|---|
修改 DOM 结构 | Reflow + Paint + Composite |
修改宽高/位置/字体等 Layout 属性 | Reflow + Paint + Composite |
修改颜色、背景等 Paint 属性 | Paint + Composite |
修改 transform , opacity | 只触发 Composite(性能好) |
实际应用:开发者如何影响渲染管线?
技术/操作 | 渲染行为 | 是否性能友好 |
---|---|---|
transform: translate() | 只触发 Composite | ✅ 非常高效 |
display: none -> block | Reflow + Paint | ❌ 慎用 |
background-color 改变 | Paint | 🟡 一般 |
width 改变 | Reflow + Paint | ❌ 重计算布局 |
使用 will-change 优化动画 | 创建独立层,避免 Paint | ✅ 高效 |
渲染管线 VS 事件循环?
渲染管线 | 事件循环 |
---|---|
负责页面“如何画出来” | 负责 JS 任务“如何调度执行” |
处理 DOM → 屏幕的全过程 | 处理 JS 同步 + 异步任务执行 |
涉及 GPU、合成、像素渲染 | 涉及调用栈、任务队列、回调调度 |
60FPS 性能优化关注点 | 异步控制流程优化关注点 |
哪些因素会影响首屏加载和性能
阻塞渲染的资源
2. JavaScript 执行太久
如果主线程执行了很长时间的 JS(例如循环、大量计算),那么:会阻塞 DOM 更新阻塞页面响应(用户点击没有反应)甚至阻塞定时器(比如 setTimeout 会延迟)
频繁的 Layout / Repaint / Reflow
CSS 操作或 DOM 操作不当会导致:多次回流(Reflow)多次重绘(Repaint)for (let i = 0; i < 1000; i++) {element.style.marginLeft = i + 'px';
}
优化建议:
-
使用 class 一次性改变样式
-
使用 documentFragment 批量操作 DOM
-
使用 will-change 提前告诉浏览器优化
首屏加载优化点总结
优化点 | 影响阶段 | 说明 |
---|---|---|
压缩/合并 JS、CSS | HTML 解析、CSSOM 构建 | 减少请求数,提升速度 |
JS 加 defer 或 async | 避免阻塞渲染 | defer 等待 DOM 构建后执行;async 并行加载 |
图片懒加载 | Paint 阶段 | 减少非首屏图片加载 |
CSS 放头部、JS 放尾部 | HTML 解析 | 避免阻塞 |
使用 Skeleton 骨架屏 | Paint 阶段 | 改善用户体验,看起来加载更快 |
使用 SSR 或 CSR + 缓存 | 全局 | 服务端渲染 + 缓存提升首屏速度 |
重要概念
-
DOM 树:HTML 标签构成的树结构。
-
CSSOM 树:CSS 规则构成的样式树。
-
Render Tree:渲染树,仅包含可见节点及其样式。
-
回流(Reflow):重新计算布局(大小、位置)。
-
重绘(Repaint):节点视觉变化(颜色、背景等)但不改变布局。
-
合成(Composite):合成多图层,最终绘制到屏幕。
什么会触发回流与重绘
操作 | 触发回流 | 触发重绘 |
---|---|---|
改变元素大小、位置(width, height, top, left) | ✅ | ✅ |
添加或删除可见元素 | ✅ | ✅ |
改变字体大小、边距 | ✅ | ✅ |
改变颜色、背景色 | ❌ | ✅ |
visibility: hidden → visible | ❌ | ✅ |
性能优化建议
-
减少回流:避免频繁修改影响布局的属性。
-
批量修改 DOM:用 DocumentFragment 或虚拟 DOM 减少操作次数。
-
CSS 动画优先用 transform 和 opacity:只触发合成,性能好。
-
用 requestAnimationFrame 控制动画帧率。
-
合理使用 will-change:提前告诉浏览器哪些元素会变,提前创建合成层。
-
避免阻塞主线程的长同步任务:避免页面卡顿。
首屏加载优化重点
-
减少阻塞资源:CSS 放头部,JS 放尾部,使用 defer 或 async。
-
避免大 JS 任务阻塞主线程。
-
图片懒加载,减少初始绘制压力。
-
服务端渲染(SSR) 提升首屏渲染速度。
-
骨架屏 提高用户感知速度