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...