重绘与重排是浏览器渲染的重要动作,对前端性能影响非常大,所以值得多了解一下 

什么是重绘与重排?

重绘是一个改变元素外观的行为,例如改变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;