重绘:当元素的属性发生改变时(如color),浏览器通知render重新描绘相应的元素。
重排:元素变化涉及元素布局,浏览器抛弃原属性,重新计算。
重绘不一定重排,重排一定导致重绘。
回流:重排好的结果,传递给render来重新绘制页面,过程叫回流。
什么会导致回流?
- 添加或者删除可见的DOM元素;
- 元素位置改变;
- 元素尺寸改变——边距、填充、边框、宽度和高度
- 内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
- 页面渲染初始化;
- 浏览器窗口尺寸改变——resize事件发生时;
如何优化减少重排带来的消耗?
1.分离读写操作。
div.style.top = "10px";
div.style.bottom = "10px";
div.style.right = "10px";
div.style.left = "10px";
console.log(div.offsetWidth);
console.log(div.offseHeight);
console.log(div.offsetRight);
console.log(div.offsetLeft);
原来的操作会导致四次重排和四次重绘,变换顺序之后只会触发一次重排 在第一个console的时候,浏览器把之前上面四个写操作的渲染队列都给清空了。因为渲染队列本来就是空的,所以剩下的console并没有触发重排,仅仅拿值而已。
2.样式集中改变
这样就不会多次地重排或重绘
//bad
var left = 10;
var top = 10;
el.style.left = left + "px";
el.style.top = top + "px";
//good
el.className += " className";
//or
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
3.缓存布局信息
// bad 强制刷新 触发两次重排
div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';
// good 缓存布局信息 相当于读写分离
var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';
4.将DOM离线
一旦我们给元素设置display:none时,元素不会存在于渲染树中,相当于将其从页面“拿掉”,我们之后的操作将不会触发重排和重绘,这叫做DOM的离线化。
- JavaScript dom.display = ‘none’ // 修改dom样式 dom.display = ‘block’
通过使用DocumentFragment创建一个dom碎片,在它上面批量操作dom,操作完成之后,再添加到文档中,这样只会触发一次重排。 - 复制节点,在副本上工作,然后替换它! 将position属性设置为absolute或fixed
- position属性为absolute或fixed的元素,重排开销比较小,不用考虑它对其他元素的影响
6.优化动画
- 可以把动画效果应用到position属性为absolute或fixed的元素上,这样对其他元素影响较小
- 动画效果还应牺牲一些平滑,来换取速度,这中间的度自己衡量:
比如实现一个动画,以1个像素为单位移动这样最平滑,但是Layout就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多。 - 启用GPU加速 GPU 硬件加速是指应用 GPU 的图形性能对浏览器中的一些图形操作交给 GPU 来完成,因为 GPU是专门为处理图形而设计,所以它在速度和能耗上更有效率。 GPU 加速通常包括以下几个部分:Canvas2D,布局合成, CSS3转换(transitions),CSS3 3D变换(transforms),WebGL和视频(video)。