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

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

如何在前端避免重排(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

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

推荐文章

在 Rust 中使用 OpenCV 进行绘图
2024-11-19 06:58:07 +0800 CST
JavaScript 实现访问本地文件夹
2024-11-18 23:12:47 +0800 CST
介绍 Vue 3 中的新的 `emits` 选项
2024-11-17 04:45:50 +0800 CST
markdown语法
2024-11-18 18:38:43 +0800 CST
用 Rust 构建一个 WebSocket 服务器
2024-11-19 10:08:22 +0800 CST
纯CSS绘制iPhoneX的外观
2024-11-19 06:39:43 +0800 CST
使用 Vue3 和 Axios 实现 CRUD 操作
2024-11-19 01:57:50 +0800 CST
在JavaScript中实现队列
2024-11-19 01:38:36 +0800 CST
Vue3中如何进行异步组件的加载?
2024-11-17 04:29:53 +0800 CST
一文详解回调地狱
2024-11-19 05:05:31 +0800 CST
PHP来做一个短网址(短链接)服务
2024-11-17 22:18:37 +0800 CST
H5抖音商城小黄车购物系统
2024-11-19 08:04:29 +0800 CST
Vue3中如何处理路由和导航?
2024-11-18 16:56:14 +0800 CST
Golang 中你应该知道的 Range 知识
2024-11-19 04:01:21 +0800 CST
Vue3中的Scoped Slots有什么改变?
2024-11-17 13:50:01 +0800 CST
程序员茄子在线接单