1. 程式人生 > >重繪和回流及優化

重繪和回流及優化

遍歷 str etc 變量 play idt clas 控制 不可

1. 瀏覽器渲染機制

  • 瀏覽器采用流式布局模型(Flow Based Layout)

  • 瀏覽器會把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合並就產生了渲染樹(Render Tree)。

  • 有了RenderTree,我們就知道了所有節點的樣式,然後計算他們在頁面上的大小和位置,最後把節點繪制到頁面上。

  • 由於瀏覽器使用流式布局,對Render Tree的計算通常只需要遍歷一次就可以完成,但table及其內部元素除外,他們可能需要多次計算,通常要花3倍於同等元素的時間,這也是為什麽要避免使用table布局的原因之一。

2. 重繪

由於節點的幾何屬性發生改變或者由於樣式發生改變而不會影響布局的,稱為重繪,例如outline, visibility, color、background-color等,重繪的代價是高昂的,因為瀏覽器必須驗證DOM樹上其他節點元素的可見性。

3. 回流

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

<body>
<div class="error">
<h4>我的組件</h4>
<p><strong>錯誤:</strong>錯誤的描述…</p>
<h5>錯誤糾正</h5>
<ol>
<li>第一步</li>

<li>第二步</li>
</ol>
</div>
</body>

在上面的HTML片段中,對該段落(<p>標簽)回流將會引發強烈的回流,因為它是一個子節點。這也導致了祖先的回流(div.error和body – 視瀏覽器而定)。此外,<h5>和<ol>也會有簡單的回流,因為這些節點在DOM中回流元素之後。大部分的回流將導致頁面的重新渲染。

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

4. 瀏覽器優化

現代瀏覽器大多都是通過隊列機制來批量更新布局,瀏覽器會把修改操作放在隊列中,至少一個瀏覽器刷新(即16.6ms)才會清空隊列,但當你獲取布局信息的時候,隊列中可能有會影響這些屬性或方法返回值的操作,即使沒有,瀏覽器也會強制清空隊列,觸發回流與重繪來確保返回正確的值。

主要包括以下屬性或方法:

  • offsetTop、offsetLeft、offsetWidth、offsetHeight

  • scrollTop、scrollLeft、scrollWidth、scrollHeight

  • clientTop、clientLeft、clientWidth、clientHeight

  • width、height

  • getComputedStyle()

  • getBoundingClientRect()

所以,我們應該避免頻繁的使用上述的屬性,他們都會強制渲染刷新隊列。

5. 減少重繪與回流

  1. CSS

  • 使用 transform 替代 top

  • 使用 visibility 替換 display: none ,因為前者只會引起重繪,後者會引發回流

  • 避免使用table布局,可能很小的一個小改動會造成整個 table 的重新布局。

  • 盡可能在DOM樹的最末端改變class,回流是不可避免的,但可以減少其影響。盡可能在DOM樹的最末端改變class,可以限制了回流的範圍,使其影響盡可能少的節點。

  • 避免設置多層內聯樣式,CSS 選擇符從右往左匹配查找,避免節點層級過多。

<div>
<a> <span></span> </a>
</div>
<style>
span {
color: red;
}
div > a > span {
color: red;
}
</style>

對於第一種設置樣式的方式來說,瀏覽器只需要找到頁面中所有的 span 標簽然後設置顏色,但是對於第二種設置樣式的方式來說,瀏覽器首先需要找到所有的 span 標簽,然後找到 span 標簽上的 a 標簽,最後再去找到 div 標簽,然後給符合這種條件的 span 標簽設置顏色,這樣的遞歸過程就很復雜。所以我們應該盡可能的避免寫過於具體的 CSS 選擇器,然後對於 HTML 來說也盡量少的添加無意義標簽,保證層級扁平。

  • 將動畫效果應用到position屬性為absolute或fixed的元素上,避免影響其他元素的布局,這樣只是一個重繪,而不是回流,同時,控制動畫速度可以選擇 requestAnimationFrame,詳見探討 requestAnimationFrame。

  • 避免使用CSS表達式,可能會引發回流。

  • 將頻繁重繪或者回流的節點設置為圖層,圖層能夠阻止該節點的渲染行為影響別的節點,例如will-change、video、iframe等標簽,瀏覽器會自動將該節點變為圖層。

  • CSS3 硬件加速(GPU加速),使用css3硬件加速,可以讓transform、opacity、filters這些動畫不會引起回流重繪 。但是對於動畫的其它屬性,比如background-color這些,還是會引起回流重繪的,不過它還是可以提升這些動畫的性能。

  1. JavaScript

    • 避免頻繁操作樣式,最好一次性重寫style屬性,或者將樣式列表定義為class並一次性更改class屬性。

    • 避免頻繁操作DOM,創建一個documentFragment,在它上面應用所有DOM操作,最後再把它添加到文檔中。

    • 避免頻繁讀取會引發回流/重繪的屬性,如果確實需要多次使用,就用一個變量緩存起來。

    • 對具有復雜動畫的元素使用絕對定位,使它脫離文檔流,否則會引起父元素及後續元素頻繁回流。

重繪和回流及優化