浏览器将 HTML、CSS、JavaScript 转换为像素的过程称为渲染,主要分为以下阶段:
解析 HTML:构建 DOM 树(Document Object Model)。
解析 CSS:生成 CSSOM 树(CSS Object Model)。
合并 DOM 和 CSSOM:形成 渲染树(Render Tree),包含可见节点及其样式。
布局(Layout):计算渲染树中节点的几何信息(位置、尺寸等),也称 回流(Reflow)。
绘制(Paint):将布局结果转换为屏幕上的像素(填充颜色、文字等)。
合成(Composite):将各图层(Layers)合并为最终页面(GPU 加速优化)。
渲染树与 DOM 树的区别:
渲染树仅包含可见节点(如忽略 display: none
的元素)。
每个渲染树节点对应一个 DOM 节点,但可能被拆分为多个渲染节点(如文本换行)。
图层(Layer):
浏览器会将某些元素(如 transform
、opacity
)提升为独立的图层,减少重绘范围。
可通过 will-change: transform
或 transform: translateZ(0)
强制提升图层。
定义:重新计算元素的几何属性(位置、尺寸),导致渲染树重新布局。
触发条件:
修改影响布局的 CSS 属性,例如:
javascript复制width, height, margin, padding, position, display, font-size, etc.
性能消耗:
回流是渲染流程中最耗性能的阶段,可能触发子节点和后续节点的连锁回流。
定义:元素的外观(颜色、背景等)发生变化,但不影响布局。
触发条件:
修改不影响几何属性的 CSS 属性,例如:
javascript复制color, background, border-radius, visibility, etc.
性能消耗:
重绘比回流轻量,但仍需重新生成像素数据。
回流必触发重绘:布局改变后,必须重新绘制。
重绘不一定触发回流:仅外观变化时,无需重新布局。
修改 DOM 结构(添加/删除节点)。
读取布局属性(如 offsetWidth
、scrollTop
),可能导致强制同步回流(Forced Synchronous Layout)。
改变布局属性(如 width
)触发回流。
改变外观属性(如 color
)触发重绘。
窗口缩放、滚动条拖动。
输入框聚焦导致页面布局变化。
批量修改 DOM:
使用 documentFragment
或虚拟 DOM(如 React/Vue)批量操作。
避免频繁读取布局属性:
将多次读取操作合并(如使用 requestAnimationFrame
)。
分离读写操作:
先读取所有布局属性,再统一修改样式。
使用 position: absolute/fixed
:
使元素脱离文档流,减少回流影响范围。
使用 CSS 动画替代 JS 动画:
利用 transform
和 opacity
(仅触发合成阶段,跳过布局和绘制)。
Debounce 或 Throttle:
控制高频事件(如 resize
、scroll
)的回调频率。
使用 CSS3 硬件加速:
通过 transform: translateZ(0)
或 will-change
将元素提升到独立图层。
javascript复制const box = document.getElementById('box');box.style.width = '100px'; // 触发回流box.style.height = '200px'; // 再次触发回流
javascript复制const box = document.getElementById('box');box.style.cssText = 'width: 100px; height: 200px;'; // 单次回流
渲染流程:DOM → CSSOM → 渲染树 → 布局 → 绘制 → 合成。
回流:布局变化,性能消耗高。
重绘:外观变化,性能消耗较低。
优化核心:减少回流次数、缩小回流范围、利用 GPU 加速