重绘与重排是浏览器渲染的重要动作,对前端性能影响非常大,所以值得多了解一下
什么是重绘与重排?
重绘是一个改变元素外观的行为,例如改变visibility、背景色等属性
重排是浏览器重新计算各个元素的排列位置,需要重新进行布局计算,例如改变元素的宽高、元素内的内容
重绘不会带来重新布局,并不一定伴随重排,但重排一定会导至重绘
哪些操作会引起重排?
(1)改变DOM元素的几何属性
某元素的几何属性发生变化时,会触发子节点、兄弟节点、祖先节点重新计算,也就是所有元素都得重新计算大小、位置,整个页面重新渲染,代价非常大
(2)DOM树的结构变化
例如节点的增减、移动等,也会触发重排
这个影响小于第一种情况,因为DOM树的遍历是从上的下,从左到右的,在这个过程中,当前元素不会影响其前面已经遍历过的元素
例如在body最前面插入一个元素,会导致整个文档的重新渲染,而在其后插入一个元素,则不会影响到前面的元素
(3)获取某些属性
当获取一些属性时,浏览器为取得正确的值也会触发重排,这些属性包括:
offsetTop、offsetLeft、 offsetWidth、offsetHeight
scrollTop、scrollLeft、scrollWidth、scrollHeight
clientTop、clientLeft、clientWidth、clientHeight
getComputedStyle()
如何减小重绘重排的性能代价?
(1)将多次改变样式的操作合并成一次
//bad
var test = document.getElementById('test');
test.style.color = '#000';
test.style.background = '#111';
//good
.test {
background: #111;
color: #000;
}
document.getElementById('test').className = 'test';
(2)适当使用绝对定位
在页面逻辑允许的情况下,可以把position属性设为absolute或fixed
这样此元素就脱离了文档流,它的变化不会影响到其他元素
例如淘宝网首页的轮播广告就使用了绝对定位,轮播需要不断修改节点,就会引起大量重排,使用绝对定位可以提高很多性能
(3)把多次对节点的操作合并为一次操作
//bad
for(var i=0; i<10; i++){
$("#test").append('hi');
}
//good
var frag = document.createDocumentFragment();
var str = '';
for(var i=0; i<10; i++){
str += 'hi';
}
$("#test").appendChild(frag);
(4)临时使用display:none
把要频繁操作的节点先置为隐藏,再对其操作,操作完成后,再显示出来
对隐藏节点的操作是对页面没有任何影响的,只是隐藏和显示这两个动作触发重排
(5)缓存属性值
在需要经常取上面提到的那些引起浏览器重排的属性值时,要缓存到变量
//bad
var a = document.body.scrollTop + 1;
var b = document.body.scrollTop + 2;
//good
var top = document.body.scrollTop;
var a = top + 1;
var b = top + 2;