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