css 重排與重繪

來源:互聯網
上載者:User

在介紹瀏覽器的重排與重繪之前,先瞭解一下瀏覽器的工作原理一旦我們瞭解了瀏覽器是如何工作的,我們就可以更好的去駕馭它。
現代瀏覽器通常擁有兩個重要的執行線程,這兩個線程相互配合來渲染出頁面: 主線程

通常情況下,主線程主要負責以下工作:運行JavaScript、計算HTML元素的CSS樣式、布局頁面、把頁面元素繪製成一個或多個位元影像、把這些位元影像移交給排版線程 排版線程

通常情況下,排版線程主要負責以下工作:通過GPU渲染位元影像,並顯示在螢幕上、向主線程請求更新位元影像的可見部分或即將可見的部分、判斷出當前頁面處於可見的部分、判斷出即將通過頁面滾動而可見的部分、隨著使用者滾動頁面來移動這些部分(可見部分的和即將可見的部分) GPU

排版線程通過GPU把位元影像繪製到了螢幕上。
GPU比較擅長於:繪製位元影像到螢幕、重複的繪製同一個位元影像、在不同的位置,以不同的旋轉角度,或者不同的縮放大小來繪製同一個位元影像。
GPU相對慢的地方:將位元影像載入到顯存裡。 重排與重繪

瀏覽器下載完頁面中的所有組件——HTML標記、JavaScript、CSS、圖片之後會解析產生兩個內部資料結構——DOM樹和渲染樹。
DOM樹表示頁面結構,渲染樹表示DOM節點如何顯示。DOM樹中的每一個需要顯示的節點在渲染樹種至少存在一個對應的節點(隱藏的DOM元素 disply值為none 在渲染樹中沒有對應的節點)。渲染樹中的節點被稱為“幀”或“盒”,符合CSS模型的定義,理解頁面元素為一個具有填充,邊距,邊框和位置的盒子。一旦 DOM和渲染樹構建完成,瀏覽器就開始顯示(繪製)頁面元素。
當DOM的變化影響了元素的幾何屬性(寬或高),瀏覽器需要重新計算元素的幾何屬性,同樣其他元素的幾何屬性和位置也會因此受到影響。瀏覽器會使渲染樹中受到影響的部分失效,並重新構造渲染樹。這個過程稱為重排。完成重排後,瀏覽器會重新繪製受影響的部分到螢幕,該過程稱為重繪。
tips:並不是所有的DOM變化都會影響幾何屬性,比如改變一個元素的背景色並不會影響元素的寬和高,這種情況下只會發生重繪。 引起重排的情況

很顯然,每次重排,必然會導致重繪,那麼,重排會在哪些情況下發生。 添加或者刪除可見的DOM元素 元素位置改變 元素尺寸改變 元素內容改變(例如:一個文本被另一個不同尺寸的圖片替代) 頁面渲染初始化(無法避免) 瀏覽器視窗尺寸改變

這些都是顯而易見的,或許你已經有過這樣的體會,不間斷地改變瀏覽器視窗大小,導致UI反應遲鈍(某些低版本IE下甚至直接掛掉),現在你可能恍然大悟,沒錯,正是一次次的重排重繪導致的。 transition

瞭解了重排與重繪之後,現在我們看一下瀏覽器的主線程和排版線程是如何協同工作來完成一個CSS Transition的。
假設我們想要將一個元素的高度值從100px轉換到200px,如下所示:

div {       height: 100px;       transition: height 1s linear;   }   div:hover {       height: 200px;   } 

主線程和排版線程會根據下圖所示時序圖來完成這個Transition。注意:在橙色方框中的操作是潛在的耗時操作,藍色方框中的操作是較快的操作。

正如你所見,整個過程有很多橙色的方框,意味著瀏覽器有相當繁重的工作要處理,也意味著這個Transition可能會出現卡頓。
在整個Transition的每一幀中,瀏覽器都要去重新布局,繪製頁面,並把最新的位元影像對象載入到GPU。我們前邊瞭解過,把位元影像對象載入到GPU的記憶體中是個相對緩慢的操作。
瀏覽器之所以要在每一幀動畫上處理如此繁重的工作是因為這個元素的內容一直在變化。修改一個元素的高度可能會引起其子項目也要相應的改變大小,因此瀏覽器必須去重新布局。重新布局後,主線程必須為該元素重建位元影像對象。 transition: transform

由此可見,對高度進行的Transition相對來說效能比較差,那有一些效能比較好的Transition嗎。
假設我們想要把一個元素從一半大小縮放到實際大小,並假設我們使用CSS的transform 屬性來對它進行縮放,同時使用CSS的transition屬性來產生縮放的動畫效果,如下所示:

div {       transform: scale(0.5);       transition: transform 1s linear;   }   div:hover {       transform: scale(1.0);   }  


我們看到只有很少的幾個橙色的方框,意味著這個動畫效果可能會很流暢。那麼,一個元素的transform動畫效果與其高度的動畫效果有什麼不同呢。
根據定義,CSS的transform屬性不會改變元素的布局,也不會影響到其周圍的元素。它把元素當做一個整體看待——縮放整個元素、旋轉整個元素或者移動整個元素。
這對瀏覽器來說是一個好訊息。瀏覽器只需在動畫開始的時候產生這個元素的位元影像對象,並把它傳遞給GPU。在這之後,瀏覽器無需再做任何重新布局,繪製頁面以及傳遞位元影像對象的操作了,相反,瀏覽器可以利用GPU擅長的繪製的特點來快速的在不同的位置,旋轉或縮放同一個位元影像對象。 設計決策

那麼,是否這就意味這我們不要去緩動一個元素的高度。非也,一些情況下,這是你的設計效果的一部分,並且動畫效果可以非常快的完成。也許動畫的元素是孤立的,不會引起頁面其他部分進行重新布局;也許該元素只是單純的進行重繪,瀏覽器可以快速的完成;也許該元素很小,瀏覽器只需將很小的位元影像對象傳遞給GPU。
當然了,在不影響你設計的視覺效果的情況下,最好去緩動一個效能較好的CSS屬性,如transform,而不是去緩動一個效能較差的CSS屬性,如height。舉例來說,假設你的設計中有一個按鈕,當點擊它的時候會出來一個菜單,試著去緩動菜單的transform屬性來顯示它而不是緩動它的top或height屬性來達到類似的效果。
在動畫上特別快的CSS屬性包括: CSS transform CSS opacity CSS filter 總結

重排和重繪是DOM編程中耗能的主要原因之一,平時涉及DOM編程時可以參考以下幾點: 盡量不要在布局資訊改變時做查詢(會導致渲染隊列強制重新整理) 同一個DOM的多個屬性改變可以寫在一起(減少DOM訪問,同時把強制渲染隊列重新整理的風險降為0) 如果要大量新增DOM,可以先讓元素脫離文檔流,操作完後再帶入文檔流,這樣只會觸發一次重排(fragment元素的應用) 將需要多次重排的元素,position屬性設為absolute或fixed,這樣此元素就脫離了文檔流,它的變化不會影響到其他元素。例如有動畫效果的元素就最好設定為絕對位置。 參考文獻 http://developer.51cto.com/art/201508/488053.htm http://www.jb51.net/css/348357.html

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.