回流(Reflow)
当Render Tree中部分或全部元素的尺寸、结构或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程成为回流
导致回流的操作
- 页面首次渲染
- 浏览器窗口大小发生变化
- 元素尺寸或位置发生改变
- 元素内容变化(文字数量和图片大小等等)
- 元素字体大小变化
- 添加或者删除可见的DOM元素
- 激活伪类元素
- 查询某些属性或调用某些方法
导致回流的属性和方法
- clientWidth、clientHeight、clientTop、clientLeft
- offsetWidth、offsetHeight、offsetTop、offsetLeft
- scrollWidth、scrollHeight、scrollTop、scrollLeft
- scrollIntoView()、scrollIntoViewIfNedded()
- getComputedStyle()
- getBoundingClientRect()
- scrollTo()
重绘
当页面中元素央视的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘
回流必将引起重绘,重绘不一定会引起回流
避免回流和重绘方法
减少回流、重绘其实就是需要减少对render tree的操作,并减少对一些style信息的请求,尽量利用好浏览器的优化策略
-
避免操作DOM,创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document。也可以在一个display:none的元素上进行操作,最终把它显示出来。因为display:none上的DOM操作不会引发回流和重绘。
-
让要操作的元素进行"离线处理",处理完后一起更新,这里所谓的"离线处理"即让元素不存在于render tree中。如读取offsetLeft等属性。
-
尽可能在DOM树的末端改变class ,尽可能在DOM树的里面改变class,可以限制回流的范围,使其影响尽可能少的节点。
-
避免设置多层内联样式,因为每一个都会造成回流,样式合并在一个外部类,这样当该元素的class属性被操作时,只会产生一个reflow。
-
将需要多次回流的元素position属性设为absolute或fixed,这样该元素就会脱离文档流,它的变化不会影响其他元素变化。比如动画效果应用到position属性为absolute或fixed的元素上。
-
牺牲平滑度换取速度,动画元素每次移动3像素可能在非常快的机器上看起来平滑度低了,但它不会导致CPU在较慢的机器和移动设备中抖动
-
避免使用table布局,在布局完全建立之前,table需要很多关口,table是可以影响之前已经进入的DOM元素的显示的元素。即使一些小的变化和会导致table中所有其他节点回流。
-
避免使用css的JavaScript表达式,该规则较过时,但是个好主意。因为每次都需要重新计算文档,或部分文档、回流。 回流时,浏览器会使渲染树中受影响的部分失效,然后重新构造这部分的render树。完成回流之后浏览器会重新布局、绘制受影响的部分到屏幕中,该过程就是重绘。所以回流必定会引起重绘,但重绘不一定引起回流。 每个页面至少需要一次回流,就是页面第一次加载时。回流变化涉及到部分页面(或整个页面)的布局。一个元素的回流导致其所有子元素以及DOM中紧随其后的祖先元素和其子元素都发生回流。
执行顺序 先回流后重绘