Skip to content
MiTu

MiTu

A Web developer who loves to Reading and photography

如何减少重绘和回流的次数

前言

一.重排(reflow)

重排也叫回流,当 DOM 的变化影响了元素的几何信息(位置、尺寸大小等),浏览器需要重新计算元素的几何属性,将其安放在界面的正确位置,这个过程叫做重排。

二.重绘(repaint)

当一个元素的外观发生变化,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。

方案

1. 浏览器对于重排和重绘的优化

浏览器会维护一个队列,把所有会引起重排、重绘的操作放入这个队列,等队列中的操作到了一定数量或者到了一定的时间间隔,浏览器就会 flush 队列,进行一个批处理。这样就会让多次的重排、重绘变成一次重排重绘。 但当你获取布局信息的操作的时候,例如 offsetTop 等方法,为了保证获取结果的准确性,就会打破浏览器的这种优化策略,强制浏览器提前 flush 队列。

2. css 中避免重排重绘

  1. 减少重排范围,尽量将需要重排的内容固定在局部范围。
  2. 不要使用 table 布局,可能很小的一个改动会造成整个 table 的重新布局。不得已使用 table 的场景,可以设置 table-layout: auto; 或者 table-layout: fixed; 这样可以让 table 一行一行的渲染,同时可可以限制重排的影响范围。
  3. 集中修改样式。这样可以尽可能利用浏览器的优化机制,一次重排重绘就完成渲染。
  4. 避免设置多项内联样式。
  5. 如果想设定元素的样式,可以通过改变元素的 class 类名(尽可能在 DOM 树的最里层)。
  6. 将 DOM 离线。通过设置元素属性 display: none; 将其从页面上去掉,然后再进行后续操作,这些后续操作将不会出发重排重绘,最后通过 display 属性显示。另外,visibility:hidden 的元素只对重绘有影响,不影响重排。
  7. 使用 position: absolute / fixed; 脱离文档流。例如那些复杂的动画,对其设置 position:absolute / fixed; 尽可能地使元素脱离文档流,从而减少对其他元素的影响。
  8. 利用 transform translate 去代替 left top 的变换。
  9. 使用 css3 硬件加速,可以让 transform、opacity、filters 这些动画不会引起重排重绘。
  10. 避免使用 css 的 JavaScript 表达式。
  11. 将频繁重排或重绘的节点设置为图层。将节点设置为 video 或 iframe;为节点添加 will-change 属性。

3. js 中避免重排和重绘

  1. 减少直接操作 DOM 元素。不要一条一条地修改 DOM 的样式,改用 className 来控制。
  2. 分离读写操作。当需要 js 操作元素样式时,即将获取样式属性的操作集中执行,并缓存值,在需要设置样式属性时也集中处理,避免获取和设置的操作互相夹杂。为获取、设置的操作都会引起重排。
  3. 动态插入多个节点时,可以使用文档碎片(DocumnetFragment),创建后一次插入,避免多次的渲染性能。DocumnetFragment 是一个保存多个元素的容器对象(保存在内存),当更新其中的一个或者多个元素时,页面不会更新。
  4. 不要把 DOM 节点的 offsetLeft 等属性值放在一个循环里当成循环里的变量。
  5. 使用 resize 事件时,做防抖和节流处理。