# 回流和重绘
回流:当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。
重绘:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。 回流必将引起重绘,而重绘不一定会引起回流。
我们需要明白,页面若发生回流则需要付出很高的代价,当页面布局和几何属性改变时就需要回流。下述情况会发生浏览器回流:
- 添加或者删除可见的DOM元素;
- 元素位置改变;
- 元素尺寸改变——边距、填充、边框、宽度和高度
- 内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
- 页面渲染初始化;
- 浏览器窗口尺寸改变——resize事件发生时;
优化方案: 减少回流、重绘其实就是需要减少对render tree的操作(合并多次多DOM和样式的修改),并减少对一些style信息的请求,尽量利用好浏览器的优化策略。
- 直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器)
- 让要操作的元素进行”离线处理”,处理完后一起更新
- 不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,利用缓存
- 让元素脱离动画流,减少回流的Render Tree的规模
那如果我们使用属性又有那些可替换的属性可以优化回流与重绘呢,一共有一下9点:
- 用transform 代替 top,left ,margin-top, margin-left... 这些位移属性
- 用opacity 代替 visibility,但是要同时有translate3d 或 translateZ 这些可以创建的图层的属性存在才可以阻止回流 但是第二点经过我的实验,发现如果不加 transform: translateZ(0) 配合opacity的话还是会产生回流的,而只用visibility 就只会产生重绘不会回流 而 opacity 加上 transform: translateZ/3d 这个属性之后便不会发生回流和重绘了
- 不要使用 js 代码对dom 元素设置多条样式,选择用一个 className 代替之。
- 如果确实需要用 js 对 dom 设置多条样式那么可以将这个dom 先隐藏,然后再对其设置
- 不要在循环内获取dom 的样式例如:offsetWidth, offsetHeight, clientWidth, clientHeight... 这些。浏览器有一个回流的缓冲机制,即多个回流会保存在一个栈里面,当这个栈满了浏览器便会一次性触发所有样式的更改且刷新这个栈。但是如果你多次获取这些元素的实际样式,浏览器为了给你一个准确的答案便会不停刷新这个缓冲栈,导致页面回流增加。 所以为了避免这个问题,应该用一个变量保存在循环体外。
- 不要使用table 布局,因为table 的每一个行甚至每一个单元格的样式更新都会导致整个table 重新布局
- 动画的速度按照业务按需决定
- 对于频繁变化的元素应该为其加一个 transform 属性,对于视频使用video 标签
- 必要时可以开启 GPU 加速,但是不能滥用