当前位置: 首页 > news >正文

在前端开发中关于reflow(回流)和repaint(重绘)的几点思考

在前端开发中,reflow(回流)和repaint(重绘)是影响网页性能的两个关键概念,下面将对它们进行详细解释,并给出减少其发生次数的方法。

文章目录

      • 什么是 Reflow(回流也叫重排)?
        • 定义
        • 触发 Reflow 的常见操作
      • 什么是 Repaint(重绘)?
        • 定义
        • 触发 Repaint 的常见操作
      • 两者关系
      • 性能影响
      • 如何减少 Reflow 和 Repaint 的次数?
        • **批量修改 DOM**
        • **使用 `requestAnimationFrame` 处理动画**
        • **避免频繁读取布局信息**
        • **开启 GPU 加速,使用 `transform` 和 `opacity` 进行动画**
        • **将元素脱离文档流后进行修改**
        • 使用position:absolute或position:fixed使元素脱离文档流修改样式
        • **使用事件委托处理大量事件**
        • **优化 CSS 加载顺序**
      • 总结

什么是 Reflow(回流也叫重排)?

定义

Reflow 指的是浏览器为了重新计算文档中元素的布局信息(元素的大小、位置、边距等几何信息)而进行的过程。当 DOM 的变化影响了元素的布局信息时,浏览器需要重新计算元素在视口内的位置和尺寸,将其安放到界面中的正确位置,这个过程就被称为 Reflow。

通俗一点讲:无论通过什么方式影响了元素的几何信息(元素在视口内的位置和大小),浏览器都需要重新计算元素在视口内的几何属性,这个过程叫做Reflow(回流或重排)。

触发 Reflow 的常见操作
  • 调整窗口大小(resize)
  • 改变字体大小
  • 添加或删除 DOM 元素
  • 元素的尺寸(宽、高、边距等)发生变化
  • 内容变化(文本数量或图片大小改变)
  • 计算元素的某些属性(如 offsetWidthscrollTop 等)

什么是 Repaint(重绘)?

定义

Repaint 是指当一个元素的外观发生改变,但没有影响到布局信息时,浏览器将元素的新外观绘制到屏幕上的过程。Repaint 的开销通常比 Reflow 小,因为它只需处理元素的视觉样式,而不需要重新计算布局。

通俗一点讲:通过构造渲染树和重排(回流)阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(元素在视口内的位置和尺寸大小),接下来就可以将渲染树的每个节点转换为屏幕上的实际像素,这个阶段就叫做重绘。

触发 Repaint 的常见操作
  • 改变元素的颜色、背景色
  • 改变元素的可见性(visibility
  • 改变元素的边框样式
  • 改变元素的阴影效果

两者关系

  • 回流一定会导致重绘,因为布局改变后外观必然变化;
  • 重绘不一定导致回流,仅样式变化不影响布局时,只需重绘。

性能影响

回流的计算成本远高于重绘,频繁的回流会导致页面卡顿,开发中需要尽量减少(如避免频繁操作DOM样式,使用transform替代位移等).

如何减少 Reflow 和 Repaint 的次数?

为了优化网页性能,应尽量减少 Reflow 和 Repaint 的发生次数,特别是在处理动画、滚动等高频操作时。以下是一些实用的优化方法:

批量修改 DOM

不要频繁地修改 DOM,而是集中修改。例如:

// 低效做法
const el = document.getElementById('myElement');
el.style.width = '100px';
el.style.height = '200px';
el.style.margin = '10px';// 高效做法:合并样式修改
const el = document.getElementById('myElement');
el.classList.add('new-style'); // 预先定义好 new-style 类// 或者使用 CSSOM
const el = document.getElementById('myElement');
const style = el.style;
style.cssText += '; width: 100px; height: 200px; margin: 10px;';
使用 requestAnimationFrame 处理动画

对于动画效果,使用 requestAnimationFrame 可以将多次修改集中到一帧中执行,避免不必要的回流:

function animate() {requestAnimationFrame(() => {// 在这里进行 DOM 修改element.style.transform = 'translateX(100px)';element.style.opacity = '0.5';});
}
避免频繁读取布局信息

当读取元素的布局信息(如 offsetWidthscrollTop 等)时,浏览器会强制刷新布局,导致回流。因此,应避免在修改 DOM 的过程中频繁读取这些值:

// 低效做法:读取和修改交替进行
const el = document.getElementById('myElement');
console.log(el.offsetWidth); // 触发回流
el.style.width = '200px';    // 修改样式
console.log(el.offsetWidth); // 再次触发回流// 高效做法:批量读取,批量修改
const el = document.getElementById('myElement');
const width = el.offsetWidth; // 读取一次
el.style.width = '200px';     // 修改
el.style.height = '300px';    // 修改
// 后续再读取其他布局信息
开启 GPU 加速,使用 transformopacity 进行动画

开启 GPU 加速,利用 css 属性 transform 、will-change 等,比如改变元素位置,我们使用 translate 会比使用绝对定位改变其 left 、top 等来的高效,因为它不会触发重排或重绘,transform 使浏览器为元素创建⼀个 GPU 图层,这使得动画元素在一个独立的层中进行渲染。当元素的内容没有发生改变,就没有必要进行重绘。

transformopacity 不会触发回流和重绘,而是使用 GPU 进行加速,性能更好:

/* 使用 transform 代替 left/top 进行位置移动 */
.element {transition: transform 0.3s ease;
}
.element:hover {transform: translateX(50px);
}
将元素脱离文档流后进行修改

对于需要进行大量修改的元素,可以先将其脱离文档流,修改完成后再放回文档中,这样只会触发两次回流(脱离和放回时):

// 1. 隐藏元素
element.style.display = 'none';// 2. 进行多次修改
element.style.width = '200px';
element.style.height = '300px';
element.style.margin = '10px';// 3. 重新显示元素
element.style.display = 'block';
使用position:absolute或position:fixed使元素脱离文档流修改样式

默认情况下,HTML元素处于文档流中,它们的位置和大小会影响其他元素。使用position:absolute和position:fixed后,元素会脱离文档流,不再影响其他元素的布局。特别适合频繁动画或定位变动的元素,比如弹窗、浮动框、下拉菜单等。

注意:不能完全避免重排和重绘,初始设置absolute或fixed本身也需要一次重排,修改某些属性(如 width height top left)依然会触发重排和重绘,只是影响范围更小了。

使用事件委托处理大量事件

对于大量元素的事件处理,使用事件委托可以减少 DOM 操作,从而减少回流和重绘:

// 不推荐:为每个元素绑定事件
document.querySelectorAll('.item').forEach(item => {item.addEventListener('click', handleClick);
});// 推荐:使用事件委托
document.getElementById('container').addEventListener('click', (e) => {if (e.target.classList.contains('item')) {handleClick(e);}
});
优化 CSS 加载顺序

确保关键 CSS 尽早加载,避免因 CSS 加载延迟导致的回流。可以使用 rel="preload" 预加载重要的 CSS 文件:

<link rel="preload" href="critical.css" as="style" onload="this.rel='stylesheet'">

总结

Reflow 和 Repaint 是浏览器渲染过程中的必要步骤,但频繁触发会导致性能问题。通过合理规划 DOM 操作、优化 CSS 选择器、使用硬件加速等方法,可以有效减少 Reflow 和 Repaint 的次数,提升网页的响应速度和用户体验。

http://www.dtcms.com/a/275505.html

相关文章:

  • MySQL 中图标字符存储问题探究:使用外挂法,毕业论文——仙盟创梦IDE
  • AI驱动的大前端内容创作与个性化推送:资讯类应用实战指南
  • 容器化改造避坑指南:传统应用迁移K8s的10个关键节点(2025实战复盘)
  • CSS flex
  • Capsule Networks:深度学习中的空间关系建模革命
  • GGE Lua 详细教程
  • 《Java Web程序设计》实验报告四 Java Script前端应用和表单验证
  • 基于Java的Markdown到Word文档转换工具的实现
  • 基于大模型的鼻咽癌全周期预测及诊疗优化研究报告
  • EPLAN 电气制图(七):电缆设计全攻略
  • 系统学习Python——并发模型和异步编程:基础实例-[使用进程实现旋转指针]
  • 代码训练LeetCode(45)旋转图像
  • 【算法笔记】7.LeetCode-Hot100-图论专项
  • 【node/vue】css制作可3D旋转倾斜的图片,朝向鼠标
  • 每日算法刷题Day46 7.12:leetcode前缀和3道题和差分2道题,用时1h30min
  • 代码训练LeetCode(46)旋转图像
  • Python爬虫实战:研究python-docx库相关技术
  • AI软件出海SEO教程
  • 26. 删除有序数组中的重复项
  • Eureka实战
  • 2025.7.12总结
  • 车载以太网-TTL
  • BaseDao 通用更新方法设计与实现
  • Qt:QCustomPlot类介绍
  • Python问题记录`No module named ‘matplotlib‘` 问题解决方案
  • 精密模具大深径比微孔尺寸检测方案 —— 激光频率梳 3D 轮廓检测
  • 论文阅读:HybridTrack: A Hybrid Approach for Robust Multi-Object Tracking
  • Java 大视界 -- 基于 Java 的大数据可视化在城市生态环境监测与保护决策中的应用(344)
  • sscanf函数使用详解
  • WinSnap 6.1.1 中文版安装教程(64位)- 详细步骤图解