重绘回流与性能优化
重绘(repaint):元素外观改变(颜色、背景)但几何不变,重新绘制像素。回流(reflow / layout):几何信息(宽高、位置)改变,需要重新布局整棵或局部渲染树。回流的开销远大于重绘,且回流几乎必然带来重绘 —— 所以“回流是性能杀手”。
常见触发回流的操作:改 width / height / margin、窗口 resize、读写 offsetWidth 等强制同步布局属性(布局抖动)、批量改 DOM 结构。优化手段:用 transform / opacity 做动画(走合成层,不触发布局);批量 DOM 操作用 DocumentFragment 或先 display: none 脱离文档流;读写分离(先读够所有布局信息再统一写);防抖 resize 监听。
- 重绘改外观、回流改几何;回流必然带重绘,开销是重绘的数倍
- transform / opacity 动画走合成层,不触发回流
- 读写分离 + 批量操作 + 防抖 resize,是三大实战手段
HTML
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <style> .box { width: 80px; height: 80px; background: #f0c33c; border-radius: 8px; transition: transform .3s; } /* transform 动画:合成层,不回流 */ .bad { transition: left .3s; position: relative; left: 0; } /* left 动画会回流 */ </style> </head> <body> <button onclick="move1()">好:transform</button> <button onclick="move2()">差:left + 强制布局</button> <div class="box" id="b1">A</div> <div class="box bad" id="b2">B</div> <script> function move1() { // 推荐写法 document.getElementById('b1').style.transform = 'translateX(200px)'; } function move2() { // 反面:改几何 + 读写交织 const el = document.getElementById('b2'); el.style.left = el.offsetLeft + 200 + 'px'; // 读布局又写布局 → 布局抖动 } // 批量插入 100 个节点:用 DocumentFragment 只回流一次 function batch() { const frag = document.createDocumentFragment(); for (let i = 0; i < 100; i++) { const li = document.createElement('li'); li.textContent = '项 ' + i; frag.appendChild(li); // 先在内存里拼好 } document.body.appendChild(frag); // 一次回流 } // 动画统一交给 rAF,与浏览器刷新率对齐 function rafAnim() { const el = document.getElementById('b1'); requestAnimationFrame(() => { el.style.transform = 'translateX(300px)'; }); } </script> </body> </html>
本节要点重绘改色回流改形;优化核心 = 用 transform/opacity 替代几何动画 + 批量 DOM + 读写分离。




