前言:前几天公司里面一个小姐姐做了个关于浏览器的回流和重绘的培训,想着自己对这块也不太懂,于是有了这篇笔记,学习记录一下。
正文如下:
浏览器渲染的步骤是:html经过渲染生成DOM树,css经过渲染生成css渲染树,两者再经过结合,生成render tree,浏览器就可以根据render tree进行画面绘制。
如果css发生变化了,需要更新页面,这时候就可能会发生回流和重绘。
注意:回流必定会引起重绘,但是重绘并不一定会引起回流。回流比重绘的代价要更高。
1.重绘repaint:
当前元素的样式(背景颜色,字体颜色)发生改变的时候,我们只需要把改变的元素重新的渲染一下即可,重绘对于浏览器的性能较小。
发生重绘的情形:改变容器的外观风格等,比如background:black等。改变外观,不改变布局,不会影响到其他的DOM。
2.回流reflow:
指浏览器为了重新渲染部分或者全部的文档而重新计算文档中元素的位置和几何构造的过程。
回流可能导致整个dom树重新构造,影响性能。
一个元素的回流导致了其所有子元素以及dom中紧随其后的祖先元素的随后的回流。
3.引起浏览器触发回流reflow的变化:
页面首次渲染
浏览器窗口大小发生改变
元素尺寸或者位置发生改变
元素的内容发生变化(文字数量或者图片大小)
元素字体大小变化
添加或者删除可见的DOM元素
激活CSS伪类(如:hover)
查询某些属性或调用某些方法:
一些常用且会导致回流的属性和方法:
clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft
scrollWidth、scrollHeight、scrollTop、scrollLeft
scrollIntoView()、scrollIntoViewIfNeeded()
getComputedStyle()
getBoundingClientRect()
scrollTo()
4.优化(尽量少回流):
css:
1、避免使用或者少用table布局
2、尽可能的在DOM树最末端改变class
3、避免设置多层内联样式
4、将动画效果应用到position属性为absolute或fixed已经脱离正常文档流的元素上(手机端动画效果应用到absolute元素上时,浏览器也会发生回流效应,因此尽量不要使用js改变元素位置操作动画效果,手机端建议CSS3动画效果,由浏览器渲染引擎进行动画绘制,性能要高于JS控制)
5、避免使用CSS表达式(如calc()动态设置元素宽高)
6、使用visibility:hidden(会重绘,不会回流) 代替 display:none (会回流)
js:
1、避免频繁操作样式,最好是一次性重写style属性,或者将样式列表定义为class,一次性更改class属性
2、避免频繁操作DOM,创建一个documentFragment,在其上面应用所有的DOM操作,最后再将其添加到文档中
3、也可以先将元素设置为display:none,再进行相关DOM操作,操作结束后,再让它显示出来。因为在display:none元素上操作DOM,并不会引起浏览器的回流和重绘
4、避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
5、对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
现代浏览器会对频繁的回流或重绘操作进行优化:
浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。
当你访问以下属性或方法时,浏览器会立刻清空队列:
clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft
scrollWidth、scrollHeight、scrollTop、scrollLeft
width、height
getComputedStyle()
getBoundingClientRect()
因为队列中可能会有影响到这些属性或方法返回值的操作,即使你希望获取的信息与队列中操作引发的改变无关,浏览器也会强行清空队列,确保你拿到的值是最精确的。