深入瀏覽器重排與重繪

2021-10-08 21:34:24 字數 3786 閱讀 9652

dom樹表示頁面結構,渲染樹表示dom節點如何顯示。dom樹中的每乙個需要顯示的節點在渲染樹種至少存在乙個對應的節點(隱藏的dom元素disply值為none 在渲染樹中沒有對應的節點)。渲染樹中的節點被稱為「幀」或「盒」,符合css模型的定義,理解頁面元素為乙個具有填充,邊距,邊框和位置的盒子。一旦dom和渲染樹構建完成,瀏覽器就開始顯示(繪製)頁面元素。

當dom的變化影響了元素的幾何屬性(寬或高),瀏覽器需要重新計算元素的幾何屬性,同樣其他元素的幾何屬性和位置也會因此受到影響。瀏覽器會使渲染樹中受到影響的部分失效,並重新構造渲染樹。這個過程稱為重排。完成重排後,瀏覽器會重新繪製受影響的部分到螢幕,該過程稱為重繪。由於瀏覽器的流布局,對渲染樹的計算通常只需要遍歷一次就可以完成。但table及其內部元素除外,它可能需要多次計算才能確定好其在渲染樹中節點的屬性,通常要花3倍於同等元素的時間。這也是為什麼我們要避免使用table做布局的乙個原因。

並不是所有的dom變化都會影響幾何屬性,比如改變乙個元素的背景色並不會影響元素的寬和高,這種情況下只會發生重繪。

不管頁面發生了重繪還是重排,它們都會影響效能

頁面布局和元素幾何屬性的改變就會導致重排 下列情況會發生重排

不同的條件下發生重排的範圍及程度會不同

某些情況甚至會重排整個頁面,比如滑動滾動條

例如:假如我要用js修改某個div的樣式

div.style.left = '10px';

div.style.top = '10px';

div.style.width = '10px';

div.style.height = '10px';

我們修改了元素的left、top、width、height屬性 ,滿足我們發生重排的條件 ,理論上會發生4次重排 ,但是實際上只會發生1次重排,因為我們現代的瀏覽器都有渲染佇列的機制 ,當我改變了元素的乙個樣式會導致瀏覽器發生重排或重繪時 ,它會進入乙個渲染佇列,然後瀏覽器繼續往下看,如果下面還有樣式修改 ,那麼同樣入隊 ,直到下面沒有樣式修改 ,瀏覽器會按照渲染佇列批量執行來優化重排過程,一併修改樣式 ,這樣就把本該4次的重排優化為1次

but,當我們寫如下**時:

div.style.left = '10px';

console.log(div.offsetleft);

div.style.top = '10px';

console.log(div.offsettop);

div.style.width = '20px';

console.log(div.offsetwidth);

div.style.height = '20px';

console.log(div.offsetheight);

還是1次重排嗎?

obviously not!此時發生了4次重排!

上文不是說瀏覽器有渲染佇列優化機制嗎? 為什麼會有4次?

這和offsetleft/top/width/height有關

offsettop、offsetleft、offsetwidth、offsetheight

clienttop、clientleft、clientwidth、clientheight

scrolltop、scrollleft、scrollwidth、scrollheight

getcomputedstyle()(ie中currentstyle)

這些會強制重新整理佇列要求樣式修改任務立刻執行

因為瀏覽器並不確定在下面的**中是否還有修改同樣的樣式,為了獲取到當前正確的的即時值不得不立刻執行渲染佇列觸發重排!!!

我們就可以對上面的**進行優化

div.style.left = '10px';

div.style.top = '10px';

div.style.width = '20px';

div.style.height = '20px';

console.log(div.offsetleft);

console.log(div.offsettop);

console.log(div.offsetwidth);

console.log(div.offsetheight);

這樣就僅僅發生1次重排了!

還是我們最初修改樣式的**

div.style.left = '10px';

div.style.top = '10px';

div.style.width = '20px';

div.style.height = '20px';

雖然現代瀏覽器有渲染佇列的優化機制,但是古董瀏覽器效率仍然底下,觸發了4次重排 ,即便這樣,我們仍然可以做出優化 ,我們需要csstext屬性合併所有樣式改變

div.style.csstext = 'left:10px;top:10px;width:20px;height:20px;';
這樣只需要修改dom一次一併處理,僅僅觸發了1次重排 ,而且只用了一行**

除了csstext以外,我們還可以通過修改class類名來進行樣式修改

div.classname = 'new-class';
這種辦法可維護性好,還可以幫助我們免除顯示性**,但是會消耗一點點的效能

div.style.left = div.offsetleft + 1 + 'px';

div.style.top = div.offsettop + 1 + 'px';

這種讀操作完就執行寫操作造成了2次重排

快取可以進行優化

var curleft = div.offsetleft;

var curtop = div.offsettop;

div.style.left = curleft + 1 + 'px';

div.style.top = curtop + 1 + 'px';

相當於是分離讀寫操作,優化為1次重排

現在我們想要向ul中迴圈新增大量li (如果ul還不存在,最好的辦法是先迴圈新增li到ul,然後再把ul新增到文件,1次重排)

var ul = document.getelementbyid('demo');

for(var i = 0; i < 1e5; i++)

我可以做出下面的優化

var ul = document.getelementbyid('demo');

ul.style.display = 'none';

for(var i = 0; i < 1e5; i++)

ul.style.display = 'block';

var ul = document.getelementbyid('demo');

var frg = document.createdocumentfragment();

for(var i = 0; i < 1e5; i++)

var ul = document.getelementbyid('demo');

var clone = ul.clonenode(true);

for(var i = 0; i < 1e5; i++)

ul.parentnode.replacechild(clone,ul);

上面的方法減少重繪和重排的原理很簡單

而改變元素就分別使用了隱藏元素、文件碎片和轉殖元素

瀏覽器重排與重繪

前幾天內推某街,被問到了醬紫乙個問題,了解瀏覽器的重繪與重排嗎?瞬間蒙住了,的確好像沒有怎麼聽說過。於是今天抽了點時間研究了下重排和重繪,這裡分享給大家。瀏覽器在頁面渲染過程中非常重要的兩個概念,即重排和重繪。了解這兩個概念對於你在今後寫 過程中,尤其是對效能要求比較高的話,有非常大的幫助。來看看這...

瀏覽器重繪與重排

當我們在做前端開發的時候,肯定會碰到操作dom的情況,在操作dom的時候,就會引起瀏覽器的重繪與重排。重繪 如果dom變化僅僅影響的了visibility outline 背景色等等非幾何屬性,此時就發生了重繪 repaint 而不是重排,因為布局沒有發生改變。重排 當dom變化影響了元素的幾何屬性...

瀏覽器重繪和重排

我的部落格地圖 前端開發崗位是乙個知識範圍比較綜合的乙個崗位,需要了解和 的知識很多,因此,可以從廣度和深度兩個方面著手,初級工程師以廣度學習為主,高階工程師以深度研究為主。重排發生的情景 頁面渲染初始化 瀏覽器視窗改變 dom元素幾何屬性 width,height 變化 可見dom元素的增刪 do...