性能优化之重绘和重排

引言💭

在之前的文章中提到了性能优化方面的问题,这篇文章继续看看性能优化中重绘(Repaint)重排(Reflow) 这两个重要概念。


一、什么是重排(Reflow)与重绘(Repaint)?

浏览器在渲染页面时,大致经历以下几个步骤:

  1. 解析HTML,构建DOM树
  2. 解析CSS,构建CSSOM树
  3. 合并DOM与CSSOM,生成渲染树
  4. 执行布局
  5. 执行绘制
  6. 合成到屏幕上

重排(Reflow) 是重新计算元素的几何信息(位置和尺寸),会影响页面中其他元素的布局。它通常发生在DOM结构变化、样式变化影响布局时。

重绘(Repaint) 是重新渲染元素的视觉样式,比如颜色、背景等发生变化,但没有改变位置或尺寸时,就只需要重绘。

重排成本远高于重绘,因为它可能会引发整个页面或某个子树的大量计算。


二、哪些属性会触发重排或重绘?

1. 会触发重排的属性

以下属性在读取时会强制浏览器进行同步布局计算,即使没有明显变更,也可能导致重排:

  • 几何属性:

    • offsetTop, offsetLeft, offsetWidth, offsetHeight
    • clientTop, clientLeft, clientWidth, clientHeight
    • scrollTop, scrollLeft, scrollWidth, scrollHeight
  • 方法调用:

    • getBoundingClientRect()
    • scrollIntoView(), scrollIntoViewIfNeeded()
  • 计算样式:

    • window.getComputedStyle()(部分属性)
  • 页面滚动:

    • window.scrollX, window.scrollY

这些属性的读取,会让浏览器立即刷新布局以获取准确结果,从而打断原本可以批量优化的渲染流程。


2. 会触发重绘但不一定触发重排的属性

某些属性仅影响元素的外观,而不会影响布局,因此只会触发重绘:

  • color
  • visibility
  • background
  • outline
  • box-shadow(仅在不影响尺寸时)

虽然重绘的性能开销小于重排,但在动画或频繁更新中仍需注意,过多的重绘也会降低帧率。


三、如何避免性能问题?实用优化建议

为了提升页面性能,应尽量减少不必要的重排与重绘。以下是几条关键建议:

1. 避免在循环中多次访问 layout 属性

ini 复制代码
//  性能低下
for (let i = 0; i < items.length; i++) {
  totalHeight += items[i].offsetHeight; // 每次都触发重排
}

//  缓存值
const height = container.offsetHeight;

2. 使用 requestAnimationFrame 批量处理样式变更

ini 复制代码
requestAnimationFrame(() => {
  element.style.width = '100px';
  element.style.height = '100px';
});

这样可以避免同步布局阻塞,并与浏览器的刷新节奏保持一致。

3. 尽量使用 GPU 加速的属性(Transform 和 Opacity)进行动画

css 复制代码
// 推荐动画属性,不会触发重排 
transform: translateX(100px);
opacity: 0.5;

避免使用 top, left, width, height 这类会引发重排的属性。

4. 让频繁变动的元素脱离文档流

将动画或频繁变化的元素设置为 position: absolutefixed,使其不影响其他元素的布局,减少全局重排的范围。


四、现代浏览器的优化机制

现代浏览器已对渲染流程进行了大量优化。例如,会将样式计算与布局延迟到渲染周期中一次性完成。然而,如果开发者在中间访问了上述强制同步属性,就会打断这一优化流程,导致所谓的"布局抖动"。


结语✒️

性能优化并非只是代码执行效率的问题,浏览器渲染机制的理解对于构建高性能Web应用同样关键。掌握重绘与重排的原理,并合理安排 DOM 操作和样式更改,可以有效减少渲染开销,让页面运行更加流畅,提升用户体验。

相关推荐
IT_陈寒12 分钟前
Vite动态导入把我坑惨了,原来要这样用才对
前端·人工智能·后端
DFT计算杂谈16 分钟前
KPROJ编译教程
java·前端·python·算法·conda
觅_19 分钟前
前端学习后端的时候 选择一个技术
前端·学习
独泪了无痕22 分钟前
CryptoJS:数据安全的JavaScript加密利器
前端·vue.js·node.js
发现一只大呆瓜1 小时前
一文搞懂 Vite 处理CommonJS包、按需编译逻辑及 Rollup 插件兼容规则
前端
Edwardwu1 小时前
写了个y-mxgraph:给 draw.io 接上了 Yjs,顺便解决了部署在 iframe 里的一堆问题
前端·typescript
其实防守也摸鱼1 小时前
软件安全与漏洞--软件安全编码
java·前端·网络·安全·网络安全·web·工具
发现一只大呆瓜2 小时前
Vite 开发预构建机制详解,搞懂 esbuild 与 Rollup 分工差异
前端·面试·vite
计算机魔术师2 小时前
【AI面试八股文 Vol.3.4:训练微调部署选型】从预训练到量化部署:LLM 工程落地如何做模型选择
人工智能·后端·面试·架构·moe·vol.3.3·vol.3.4
九九落3 小时前
前端获取经纬度完全指南:从Geolocation API到地图集成
前端·获取经纬度