重绘:某些元素的外观被改变,例如:元素的填充颜色
重排(回流):重新生成布局,重新排列元素。
-
减少重排、重绘优化性能,其中减少重排尤为重要。重新绘制受到此次重排影响的部分,比如改变元素高度,这个元素乃至周边dom都需要重新绘制。重绘不一定导致重排,但重排一定会导致重绘。
-
引起重排的原因(掘金+简书的搬运工)
a. 页面初始渲染,这是开销最大的一次重排
b. 添加/删除可见的DOM元素
c. 改变元素位置
d. 改变元素尺寸,比如边距、填充、边框、宽度和高度等
e. 改变元素内容,比如文字数量,图片大小等
f. 改变元素字体大小
g. 改变浏览器窗口尺寸,比如resize事件发生时激活CSS伪类(例如::hover)
h. 设置 style 属性的值,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow
i. 查询某些属性或调用某些计算方法:offsetWidth、offsetHeight等,除此之外,当我们调用 getComputedStyle方法,或者IE里的 currentStyle 时,也会触发重排,原理是一样的,都为求一个“即时性”和“准确性”。 -
减少重绘的方法:减少重排(c-i)+减少重排范围(a-b)
a. 尽可能在低层级的DOM节点上,简言之如果想要改变某元素的样式,class就不要加在父元素上。
b. 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围。
c. 避免设置大量的style属性,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow,所以最好是使用class属性
d. 使用绝对定位会使的该元素单独成为渲染树中 body 的一个子元素,重排开销比较小,不会对其它节点造成太多影响。当你在这些节点上放置这个元素时,一些其它在这个区域内的节点可能需要重绘,但是不需要重排。
e. 动画实现的速度的选择。比如实现一个动画,以1个像素为单位移动这样最平滑,但是reflow就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多。
f. 不要频繁的操作样式,对于一个静态页面来说,明智且可维护的做法是更改类名而不是修改样式,对于动态改变的样式来说,相较每次微小修改都直接触及元素,更好的办法是统一在 cssText 变量中编辑。
g. 分离读写操作// bad 强制刷新 触发四次重排+重绘 div.style.left = div.offsetLeft + 1 + 'px'; div.style.top = div.offsetTop + 1 + 'px'; div.style.right = div.offsetRight + 1 + 'px'; div.style.bottom = div.offsetBottom + 1 + 'px'; // good 缓存布局信息 相当于读写分离 触发一次重排+重绘 var curLeft = div.offsetLeft; var curTop = div.offsetTop; var curRight = div.offsetRight; var curBottom = div.offsetBottom; div.style.left = curLeft + 1 + 'px'; div.style.top = curTop + 1 + 'px'; div.style.right = curRight + 1 + 'px'; div.style.bottom = curBottom + 1 + 'px';
h. DOM离线,不在当前dom树中进行操作。(1)使用 display:none,一旦我们给元素设置 display:none 时(只有一次重排重绘),元素便不会再存在在渲染树中,相当于将其从页面上“拿掉”,我们之后的操作将不会触发重排和重绘,添加足够多的变更后,通过 display属性显示(另一次重排重绘)。通过这种方式即使大量变更也只触发两次重排。另外,visibility : hidden 的元素只对重绘有影响,不影响重排。(2)通过 documentFragment 创建一个 dom 碎片,在它上面批量操作 dom,操作完成之后,再添加到文档中,这样只会触发一次重排。(3)复制节点,在副本上工作,然后替换它!
i. 动画优化。(1)可以把动画效果应用到 position属性为 absolute 或 fixed 的元素上,这样对其他元素影响较小。(2)动画效果还应牺牲一些平滑,来换取速度,这中间的度自己衡量:比如实现一个动画,以1个像素为单位移动这样最平滑,但是Layout就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多.(3)启用GPU加速.GPU 硬件加速是指应用 GPU 的图形性能对浏览器中的一些图形操作交给 GPU 来完成,因为 GPU 是专门为处理图形而设计,所以它在速度和能耗上更有效率。GPU 加速通常包括以下几个部分:Canvas2D,布局合成, CSS3转换(transitions),CSS3 3D变换(transforms),WebGL和视频(video)。