回流重绘

什么是回流重绘

HTML中每个元素都可视为一个盒子,在浏览器解析时

  • 回流:当元素的尺寸、位置或某些属性发生变化时,浏览器需要重新计算元素的几何属性,然后再将计算的结果绘制出来。这个过程就叫做回流。例如,修改元素的宽度、高度、或者添加或删除可见的DOM元素,都会触发回流。
  • 重绘:当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

回流必将引起重绘,而重绘不一定会引起回流

回流触发时机

回流一般在于元素的几何信息(大小、位置)发生变化时触发。

  1. 添加或删除节点
  2. 元素大小或位置改变
  3. 页面初次渲染
  4. 浏览器窗口尺寸变化(因为回流根据视口来计算的)

除此之外一些获取几何信息的属性也会触发回流

offsetTop offsetLeft offsetWidth offsetHeight
scroll-
client-
getBoundingClientRect() getComputedStyle()

重绘触发时机

  1. 颜色、阴影的修改
  2. 通过visibility、opacity 显示和隐藏
  3. 文本对齐方向

修改文本排列方向是会回流的,修改对齐方向不回流

浏览器优化

由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列

当你获取布局信息的操作的时候,会强制队列刷新,包括前面讲到的offsetTop等方法都会返回最新的数据

因此浏览器不得不清空队列,触发回流重绘来返回正确的值

如何减少回流重绘

  1. 通过改变元素的 class 类名设定元素的样式:这样做可以一次性地应用多个样式,而不需要逐个修改样式属性。这样可以减少浏览器重新计算样式和布局的次数,从而减少回流和重绘。
  2. 避免设置多项内联样式:内联样式会直接修改元素的样式,每修改一次都可能触发回流和重绘。使用class类名可以一次性地应用多个样式,减少回流和重绘的次数。
  3. 应用元素的动画,使用 position 属性的 fixed 值或 absolute 值:这样可以使元素脱离文档流,其位置的改变不会影响到其他元素的布局,从而减少回流。但是,这可能会增加重绘的次数,因为元素的位置改变可能会改变其可见性。
  4. 避免使用 table 布局:table 中每个元素的大小以及内容的改动,都会导致整个 table 的重新计算,从而触发回流。使用其他布局方式,如 flex 或 grid,可以减少回流的次数。
  5. 对于那些复杂的动画,对其设置 position: fixed/absolute:这样可以使元素脱离文档流,其位置的改变不会影响到其他元素的布局,从而减少回流。但是,这可能会增加重绘的次数,因为元素的位置改变可能会改变其可见性。
  6. 使用css3硬件加速:硬件加速可以让一些复杂的动画(如 transform、opacity、filters)在 GPU 而不是 CPU 上运行,这可以避免触发回流和重绘,从而提高性能。
  7. 避免使用 CSS 的 JavaScript 表达式:CSS 的 JavaScript 表达式会在每次页面渲染时都被重新计算,这可能会触发大量的回流和重绘。避免使用它们可以减少回流和重绘的次数。