写在前面
在讨论回流(重排)与重绘之前,先了解具体的浏览器解析渲染机制:
- 解析HTML,生成
DOM
树,解析CSS,生成CSSOM
树 - 将
DOM
树和CSSOM
树结合,生成渲染树 (Render Tree) - 布局(Layout):根据渲染树将
DOM
节点树每一个节点布局到屏幕上的正确位置 - 绘制(Painting):绘制所有节点,为每一个节点适用对应的样式,绘制到屏幕上
在页面初始渲染阶段,回流不可避免的触发,可以理解成页面一开始是空白的元素,后面添加了新的元素使页面布局发生改变。
回流 (Reflow)
回流(重排)
:当渲染树中的元素的布局(如:尺寸、位置)发生改变时,重新生成布局,重新排列元素。
回流的触发条件
- 页面首次渲染
- 浏览器窗口大小发生改变
- 添加/删除可见的DOM元素
- 改变元素位置
- 改变元素尺寸,比如边距、填充、边框、宽度和高度等
- 改变元素内容,比如文字数量等
- JS获取Layout属性值(
offsetLeft
、scrollTop
、getComputedStyle
等)
重绘 (Repaint)
重绘
:当渲染树中的元素外观(如:颜色、背景、visibility
)发生改变,不影响布局时,产生重绘。
注意:回流必将引起重绘,而重绘不一定会引起回流
重绘的触发条件
- 颜色的修改
- 文本方向的修改
- 阴影的修改
visibility
background
- 等等……
如何避免触发回流和重绘
- 避免频繁使用
style
,而是采用修改class
的方式。 - 将动画效果应用到
position
属性为absolute
或fixed
的元素上。 - 避免使用
CSS
表达式(例如:calc()
)。 - 避免频繁操作
DOM
,创建一个DocumentFragment
,在它上面应用所有DOM
操作,最后再把它添加到文档中。 - 对于
resize
、scroll
等进行防抖/节流处理。 - 使用
CSS3
硬件加速,可以让transform
、opacity
、filters
这些属性不会引起回流重绘
也可以先将元素设置为 display: none
,操作结束后再把它显示出来。因为在 display
属性为 none
的元素上进行的 DOM
操作不会引发回流和重绘。(这个过程称为离线操作)