强制重排重绘应避开直接读取offsetTop等后立即改样式,需合并读取、延后布局读取时机,用transform/opacity替代高代价属性,虚拟滚动优化大量DOM节点。
直接读取 offsetTop、clientWidth、getComputedStyle() 后立刻修改样式,会触发同步布局计算(Layout),在动画帧中尤其致命。浏览器不得不中断渲染流水线,回溯计算几何信息,造成卡顿。
element.getBoundingClientRect() 结果再取 top 和 width
requestAnimationFrame 回调开头就读取布局信息;应放在回调末尾,或用 setTimeout(() => {}, 0) 推迟到下一帧(仅限非动画场景)transform 和 opacity 替代 top/left/width 等触发布局的属性做动画不是所有样式变更代价相同。现代浏览器将渲染流水线分为 Layout(计算位置大小)、Paint(填充像素)、Composite(图层合成)。关键在于让动画只走 Composite 阶段。
transform(含 translate3d)、opacity
height、width、margin、padding、border、font-size
will-change: transform 可提前提示浏览器升层,但别滥用——长期开启会占用额外内存和 GPU 资源当列表项超过几百条,哪怕只是 display: none,DOM 树深度和节点数仍会拖慢样式计算与布局。虚拟滚动(virtual scrolling)不是“可选优化”,而是必要手段。
IntersectionObserver 替代 scroll 事件监听,避免频繁触发重排div 保持滚动高度不变innerHTML 中拼接长 HTML 字符串;改用 documentFragment 或 createElement 批量插入
const fragment = document.createDocumentFragment();
for (let i = 0; i < visibleItems.length; i++) {
const el = document.createElement('li');
el.textContent = visibleItems[i];
fragment.appendChild(el);
}
listElement.appendChild(fragment);
HTML5 页面里用 做图表、游戏或粒子效果时,性能瓶颈往往不在 GPU,而在 CPU 的 JS 执行和 Canvas API 调用开销。
ctx.clearRect(0,
0, width, height) —— 改用 ctx.save()/ctx.restore() 或局部擦除beginPath() → moveTo() → ...);预生成 Path2D 对象复用will-read-frequently 属性(const canvas = document.createElement('canvas', { 'will-read-frequently': true }))可提升 getImageData 性能,但会禁用硬件加速,需权衡offsetHeight 读取混在滚动节流函数里,或者给 2000 个 div 同时加 transition: all。定位得靠 Chrome DevTools 的 Rendering 面板 + FPS meter,而不是猜。