天天看點

重繪(repaint)和回流(reflow)以及據此對網頁的優化

參考:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/24

https://www.jianshu.com/p/af0b398602bc

1. 浏覽器渲染機制

  1. 解析HTML,生成DOM樹,解析CSS,生成CSSOM樹
  2. 将DOM樹和CSSOM樹結合,生成渲染樹(Render Tree)
  3. Layout(回流):根據生成的渲染樹,進行回流(Layout),得到節點的幾何資訊(位置,大小)
  4. Painting(重繪):根據渲染樹以及回流得到的幾何資訊,得到節點的絕對像素
  5. Display:将像素發送給GPU,展示在頁面上。(這一步其實還有很多内容,比如會在GPU将多個合成層合并為同一個層,并展示在頁面中。而css3硬體加速的原理則是建立合成層,這裡我們不展開,之後有機會會寫一篇部落格)
  • PS:

    table

    及其内部元素除外,他們可能需要多次計算,通常要花3倍于同等元素的時間,這也是為什麼要避免使用

    table

    布局的原因之一。
重繪(repaint)和回流(reflow)以及據此對網頁的優化

2. 重繪

由于節點的幾何屬性發生改變或者由于樣式發生改變而不會影響布局的,稱為重繪,例如

outline

visibility

color

background-color

等,重繪的代價是高昂的,因為浏覽器必須驗證DOM樹上其他節點元素的可見性。(即是對一個DOM的重新繪制)

3. 回流

回流是布局或者幾何屬性需要改變就稱為回流。回流是影響浏覽器性能的關鍵因素,因為其變化涉及到部分頁面(或是整個頁面)的布局更新。一個元素的回流可能會導緻了其所有子元素以及DOM中緊随其後的節點、祖先節點元素的随後的回流。(涉及到整體頁面的重新布局)

何時回流重繪?

  • 添加或删除可見的DOM元素
  • 元素的位置發生變化
  • 元素的尺寸發生變化(包括外邊距、内邊框、邊框大小、高度和寬度等)
  • 内容發生變化,比如文本變化或圖檔被另一個不同尺寸的圖檔所替代。
  • 頁面一開始渲染的時候(這肯定避免不了)
  • 浏覽器的視窗尺寸變化(因為回流是根據視口的大小來計算元素的位置和大小的)

回流必定會發生重繪,重繪不一定會引發回流。

4. 浏覽器優化

4.1 減少重繪與回流

4.1.1CSS

  • 使用 

    transform

     替代 

    top

  • 使用 

    visibility

     替換 

    display: none

     ,因為前者隻會引起重繪,後者會引發回流(改變了布局
  • 避免使用

    table

    布局,可能很小的一個小改動會造成整個 

    table

     的重新布局。
  • 盡可能在

    DOM

    樹的最末端改變

    class

    ,回流是不可避免的,但可以減少其影響。盡可能在DOM樹的最末端改變class,可以限制了回流的範圍,使其影響盡可能少的節點。
  • 避免設定多層内聯樣式,CSS 選擇符從右往左比對查找,避免節點層級過多。應該盡可能的避免寫過于具體的 CSS 選擇器,然後對于 HTML 來說也盡量少的添加無意義标簽,保證層級扁平。
<div>
  <a> <span></span> </a>
</div>
<style>
  span {
    color: red;
  }
  div > a > span {
    color: red;
  }
</style>
/**對于第一種設定樣式的方式來說,浏覽器隻需要找到頁面中所有的 span 标簽然後設定顔色,
但是對于第二種設定樣式的方式來說,浏覽器首先需要找到所有的 span 标簽,
然後找到 span 标簽上的 a 标簽,最後再去找到 div 标簽,然後給符合這種條件的 span 标簽設定顔色,
這樣的遞歸過程就很複雜。**/
           
  • 将動畫效果應用到

    position

    屬性為

    absolute

    fixed

    的元素上,避免影響其他元素的布局,這樣隻是一個重繪,而不是回流,同時,控制動畫速度可以選擇 

    requestAnimationFrame

    ,詳見探讨 requestAnimationFrame。
  • 避免使用

    CSS

    表達式,可能會引發回流。
  • 将頻繁重繪或者回流的節點設定為圖層,圖層能夠阻止該節點的渲染行為影響别的節點,例如

    will-change

    video

    iframe

    等标簽,浏覽器會自動将該節點變為圖層。
  • CSS3 硬體加速(GPU加速),使用css3硬體加速,可以讓

    transform

    opacity

    filters

    這些動畫不會引起回流重繪 。但是對于動畫的其它屬性,比如

    background-color

    這些,還是會引起回流重繪的,不過它還是可以提升這些動畫的性能。

4.2JavaScript

  • 避免頻繁操作樣式,最好一次性重寫

    style

    屬性,或者将樣式清單定義為

    class

    并一次性更改

    class

    屬性。
  • 避免頻繁操作

    DOM

    ,建立一個

    documentFragment

    ,在它上面應用所有

    DOM操作

    ,最後再把它添加到文檔中。
  • 避免頻繁讀取會引發回流/重繪的屬性,如果确實需要多次使用,就用一個變量緩存起來。
  • 對具有複雜動畫的元素使用絕對定位,使它脫離文檔流,否則會引起父元素及後續元素頻繁回流。