编程 如何在前端避免重排(Reflow)和重绘(Repaint)

2024-11-19 02:28:18 +0800 CST views 531

如何在前端避免重排(Reflow)和重绘(Repaint)

重排(Reflow)和 重绘(Repaint)是浏览器在处理页面渲染时的两大性能开销,频繁的重排和重绘会导致页面响应变慢、卡顿,影响用户体验。因此,减少和避免重排和重绘是前端优化的关键。

1. 避免重排(Reflow)

重排发生在当页面布局变化时,例如修改元素的尺寸、位置或在 DOM 中新增、删除元素。这是最消耗性能的操作之一。

1.1. 减少DOM操作

DOM 操作是引发重排的主要原因之一。尽量减少频繁的 DOM 结构变化,使用批量操作技术来减少性能损耗。

  • 方法:使用 DocumentFragment 或者一次性更新 DOM,避免逐个操作 DOM。
let fragment = document.createDocumentFragment();
let div = document.createElement('div');
fragment.appendChild(div);
document.body.appendChild(fragment);

1.2. 避免使用特定属性

有些属性会强制触发重排,例如:

  • offsetWidth
  • offsetHeight
  • scrollTop
  • clientWidth

在读取这些属性时,浏览器会立即重新计算页面布局,导致性能下降。避免频繁读取这些属性,或者缓存它们的值。

1.3. 使用CSS动画而非JavaScript

尽量使用 CSS 动画过渡效果 来代替 JavaScript 的样式变化,因为 CSS3 动画利用硬件加速,可以避免频繁触发重排。

1.4. 利用 position: absoluteposition: fixed

对于不需要参与页面文档流的元素,使用 position: absoluteposition: fixed,减少其影响其他元素的重排。

1.5. 使用 display: none

隐藏元素时,使用 display: none,它不会占据空间,也不会导致重排;相比之下,visibility: hidden 仅隐藏元素,但它仍然占据空间,可能引发页面重排。

1.6. 使用 requestAnimationFrame

将多个 DOM 操作放在 requestAnimationFrame 中,使浏览器可以在下一帧之前批量处理所有变更,减少中间无效的重排。

requestAnimationFrame(() => {
  // 批量处理 DOM 操作
});

2. 避免重绘(Repaint)

重绘是当元素外观发生变化时(如颜色、背景图像变化)浏览器需要重新绘制的过程,虽然它比重排消耗小,但频繁的重绘也会影响性能。

2.1. 使用 will-change 属性

will-change 告诉浏览器即将发生变化的样式,提前做好优化准备,减少不必要的重绘。

.element {
  will-change: transform;
}

2.2. 使用合成层

通过使用 translateZ(0)translate3d(0, 0, 0) 等属性将元素移入 GPU 加速的合成层,这样能将它们从主文档流中分离出来,避免影响其他元素。

.element {
  transform: translateZ(0);
}

2.3. 使用离屏Canvas

对于复杂的图形操作,可以先在离屏 Canvas 中绘制,再将结果绘制到屏幕上,避免频繁的重绘。

2.4. 使用 display: contents

display: contents 可以使元素只作为 DOM 容器存在,而不会在渲染树中产生任何视觉边界,从而减少不必要的重绘。

2.5. 使用 CSS 变量

使用 CSS 变量 可以减少重绘开销,尤其是在需要频繁改变样式时。

2.6. 避免昂贵的样式属性

尽量避免使用如 clip-pathfiltermix-blend-mode 等性能开销大的属性,因为它们可能导致大量重绘。


3. 总结

为了避免重排和重绘,以下几条策略非常关键:

  • 批量操作 DOM,尽量减少 DOM 操作次数。
  • 使用合成层,将频繁变化的元素放到单独的合成层。
  • 使用 will-change 提前通知浏览器进行优化。
  • 减少使用昂贵的 CSS 属性,例如 filterclip-path

通过这些优化技术,可以显著提高页面性能和用户体验。
images

复制全文 生成海报 前端开发 性能优化 网页设计

推荐文章

Vue3中的组件通信方式有哪些?
2024-11-17 04:17:57 +0800 CST
CentOS 镜像源配置
2024-11-18 11:28:06 +0800 CST
如何在Rust中使用UUID?
2024-11-19 06:10:59 +0800 CST
JavaScript数组 splice
2024-11-18 20:46:19 +0800 CST
网络数据抓取神器 Pipet
2024-11-19 05:43:20 +0800 CST
Node.js中接入微信支付
2024-11-19 06:28:31 +0800 CST
Vue3中如何实现国际化(i18n)?
2024-11-19 06:35:21 +0800 CST
实现微信回调多域名的方法
2024-11-18 09:45:18 +0800 CST
MySQL死锁 - 更新插入导致死锁
2024-11-19 05:53:50 +0800 CST
2025年,小程序开发到底多少钱?
2025-01-20 10:59:05 +0800 CST
Go 并发利器 WaitGroup
2024-11-19 02:51:18 +0800 CST
前端开发中常用的设计模式
2024-11-19 07:38:07 +0800 CST
Python实现Zip文件的暴力破解
2024-11-19 03:48:35 +0800 CST
批量导入scv数据库
2024-11-17 05:07:51 +0800 CST
jQuery `$.extend()` 用法总结
2024-11-19 02:12:45 +0800 CST
JavaScript中设置器和获取器
2024-11-17 19:54:27 +0800 CST
程序员茄子在线接单