reflow 也译为重排
浏览器渲染流程
reflow 回流 / 重排
- 从图中可以看出,页面至少经历一次reflow(除非是完全空白的页面),也就是初始化的时候
- 触发:对 DOM 操作导致 DOM 尺寸等属性的变化(比如修改元素的
width
、height
、top
)时,浏览器需要重新计算元素的属性,然后再将计算的结果绘制出来,这个过程叫做回流。 - 常见的会引起回流的操作有:
- 页面首次加载
- 浏览器窗口尺寸改变
- 元素尺寸或位置改变
- 元素内容变化
- 元素字体大小变化
- 增删 DOM 元素
- 查询或调用某些特定属性方法(为了确保数据的准确性)
- offsetTop、offsetLeft、offsetWidth、offsetHeight
- scrollTop、scrollLeft、scrollWidth、scrollHeight
- clientTop、clientLeft、clientWidth、clientHeight
- width、height
- getComputedStyle()
- getBoundingClientRect()
repaint 重绘
- 触发:对 DOM 操作简单修改样式(比如修改元素的
visibility
、color
、background-color
等)、却并未影响页面布局时,浏览器不需重新计算元素的位置尺寸等,直接为该元素绘制新的样式。
两者关系
- reflow 必定引起 repaint,但 repaint 不会导致 reflow
- reflow 比 repaint 的代价大
现代浏览器对性能的优化(浏览器层面)
因为频繁修改 DOM
或 CSSOM
本身是件特别耗费性能的事情,现代浏览器大多对于都做了一定的优化。比如会把一系列的操作放进队列机制来批量更新布局,至少一个浏览器刷新帧 16ms(即大多数显示屏幕的刷新率为 60Hz,一个刷新间隔为 1000ms/60)才会清空队列(节流优化~)。
但在获取布局尺寸等信息的时候,为了保证数据的准确性,队列中无论有没有会影响这些属性或方法返回值的操作,浏览器也会强制清空队列,触发回流与重绘。( IE 不保证有这些优化)
offsetTop
、offsetLeft
、offsetWidth
、offsetHeight
scrollTop
、scrollLeft
、scrollWidth
、scrollHeight
clientTop
、clientLeft
、clientWidth
、clientHeight
width
、height
getComputedStyle()
-
代码中优化回流和重绘
减少使用
CSS
表达式;- 使用
transform
替代top
; - 离线操作 DOM:把元素脱离文档流,然后对元素进行修改,这样只会导致重绘,而不会造成回流。
display:none
:临时把元素 脱离文档流,进行批量操作后再放回。这样只会有一次回流;createDocumentFragment
:创建文档片段,一次性把内容放进文档;
- 尽可能在
DOM
树的最末端改变class
:减小回流的范围; - 将动画效果应用到
position
属性为absolute
或fixed
的元素上,避免影响其他元素的布局,这样只是一个重绘,而不是回流; - JS 避免频繁读取会引发回流/重绘的属性:如果需要频繁使用,可以用变量把它缓存下来。