重排 和 重绘

103 阅读2分钟

重排(回流/布局):

  • 定义:当HTML元素的几何(尺寸/位置)属性变化,导致浏览器重新计算布局的过程
  • 触发:
    • 修改尺寸(width/height)/位置(margin/padding)信息
    • 调整窗口大小和设备方向变化
    • 增删可见的dom
    • 读取布局(offsetWidth / clineHeight)信息会强制同步重排(性能敏感)
  • 影响:重排会触发重绘,会引发整个渲染树重新计算,开销大

重绘:

  • 定义:元素外观(颜色,背景)变化,但不影响布局时,浏览器重新绘制受影响区域
  • 触发:
    • 颜色/背景/边框颜色(border-color)等样式
    • 不涉及几何变化的css动画(opacity)
  • 影响:开销比重排小,但还是应该尽量避免高频触发

页面渲染的过程:

  • 流程:解析 -> 渲染树 -> 重排(回流/布局) -> 重绘(绘制) -> 合成
  1. 解析html
    • 浏览器逐行解析html生成dom树
    • 遇到script标签时会阻塞暂停解析,并执行JavaScript(除非script标签上注明属性 async/defer)
  2. 解析css
    • 解析css生成cssom树
  3. 合并渲染树
    • 将dom树和cssom树合并,生成渲染树 render tree
    • 渲染树仅包含可见元素(display:none 排除);
  4. 布局
    • 计算节点的几何信息;
  5. 绘制
    • 将渲染树转化为屏幕上的像素,包含文本,颜色等视觉样式部分
  6. 合成
    • 将多个图层按顺序合成显示在屏幕上

如何优化页面渲染速度:

  • 关键策略:
    • 减少重排和重绘的频率
  • 减少重排:
    • 批量修改DOM: 使用 documentFragment 或 虚拟dom(React / vue)
    • 避免逐行读取布局属性(先读取 后写入)
    • 使用css transform 或 position: absolute / fixed 等脱离文档流
  • 减少重绘:
    • 使用css3动画(transform / opacity) 触发 GPU 加速(合成层)
    • 将频繁变动的元素提升为合成层(will-change: transform)

如何查看页面的重排和重绘:

  • 浏览器控制台 Performance 面板

示例:

// 低效:触发多次重排
element.style.width = '100px';
element.style.height = '200px';

// 高效:合并修改(现代浏览器可能自动优化)
element.style.cssText = 'width: 100px; height: 200px;';

// 使用 transform 避免重排(GPU 加速)
element.style.transform = 'translateX(100px)';