【筆記】web 的迴流與重繪及優化

最近看了幕課網 web 前端性能優化的課程,其中說到了瀏覽器的迴流(reflow) 及 重繪(repaint)。以爲之後面試或許會被問到因此作一下筆記:javascript

 

課程從迴流及重繪這兩個點延伸出了一個知識點就是 "css 會影響 javascrip 執行時間致使 javascript 腳本變慢"。css

瀏覽器渲染一個網頁的時候會啓用兩條線程:一條渲染javascript 腳本,另外一條渲染 ui 即css 樣式的渲染。但這兩條線程是互斥的。當javascript 線程運行的時候 ui 線程則會停止暫停,反之亦然。html

那這是爲何呢?前端

緣由是,當ui 線程運行對頁面進行渲染的時候 js 腳本不免會涉及到頁面視圖上的一些樣式的改變,爲了使這個改變動加準確 js 腳本只好等待ui 線程渲染完成的時候纔去執行。java

因此當一個頁面的元素樣式改動頻繁的時候ui 線程就會持續渲染,形成js 代碼反應慢半拍,卡頓的狀況。web

 

 

那回流和重繪到底是什麼呢?爲何他們的威力會那麼大呢?面試

迴流:當render tree 的一部分或所有的元素因改變了自身的寬高,佈局,顯示或隱藏,或者元素內部的文字結構發生變化 致使須要從新構建頁面的時候,迴流就產生了chrome

重繪:當一個元素自身的寬高,佈局,及顯示或隱藏沒有改變,而只是改變了元素的外觀風格的時候,就會產生重繪。例如你改變了元素的background-color....canvas

所以得出了一個結論:瀏覽器

迴流一定觸發重繪,而重繪不必定觸發迴流

 

觸發迴流的css 屬性有這些:

 

 

而觸發重繪的有這些:

 

如今咱們知道了那些屬性會觸發迴流,那如何避免迴流呢?

其實有兩個方法:第一,不使用以上能觸發圖層迴流的屬性,第二,創建一個圖層,讓迴流在這些圖層裏面進行,限制迴流和重繪的範圍,減小瀏覽器的運算工做量

 

先說說圖層吧

css 中有一個重要的概念的就是 "劃分圖層"。

在頁面加載完dom以後,瀏覽器會根據自身制定的一些特殊css 屬性對頁面進行劃分爲一個個圖層。例如:一些有着 position: absolute 屬性的元素他們會被瀏覽器概括到一個圖層中,而另一些 position: fixed 的元素也會被瀏覽器概括到另一個圖層中,還有一些例如:transform: translateZ(0)....  這些屬性都是視瀏覽器廠商制定的

 

圖層的優勢就是:當一個元素在本身圖層內發生變化的時候它的迴流和重繪只會在圖層內部發生,從而減小了瀏覽器對於重繪與迴流的運算量。

 

那圖層內部究竟幹了什麼呢?

 

首先,圖層對圖層裏面的節點作迴流和重佈局運算,計算出他們的樣式

 

而後,對它們生成圖形和位置

 

緊跟着,將每一個節點繪製填充到圖層位圖中

 

再而後,圖層做爲紋理髮送到GPU 上

 

最後,將全部圖層合併,顯示在瀏覽器的頁面上

 

圖層雖好,可是若是濫用圖層的話就會讓頁面由於進行了太多合併運算致使頁面卡頓。

 

因此說,圖層的用途應該讓給那些常常要進行位置結構,佈局變換的元素去使用。例如輪播圖

 

那咱們如建立一個圖層呢?

就拿chrome 來講,建立一個圖層要有如下其中一個條件:

1:一個dom 元素擁有 3d 或 透視變換的css 屬性(persepective, transform)

2:video 標籤

3:擁有3d 上下文或加速 2d 上下文的 canvas 節點

4:混合插件 flash

5:本身作的opacity 動畫 或 使用一個動畫 webkit 變換的元素

6:擁有 translate3d 或 translateZ 這兩會使 GPU 加速的屬性

7:一個包含複合層子節點的元素。(有點繞,能夠這樣想:其實自己整個網頁頁面就是一個圖層,html 標籤下包含着若干的標籤 head, body,..... 這樣便知足了這個條件了)

8:元素有一個其 z-index 比它低的兄弟節點。因爲 z-index 控制的是元素上下層的關係,因此當上下層關係變換的時候就須要一個圖層去渲染,所以知足這個條件的元素也會被建立一個圖層

可是在個人實驗中發現第7 和 8是沒有被變成圖層的,不知道爲嘛.......

 

 

那若是咱們使用屬性又有那些可替換的屬性能夠優化迴流與重繪呢,一共有一下9點:

1:用transform 代替 top,left ,margin-top, margin-left... 這些位移屬性

2:用opacity 代替 visibility,可是要同時有translate3d 或 translateZ 這些能夠建立的圖層的屬性存在才能夠阻止迴流

可是第二點通過個人實驗,發現若是不加 transform: translateZ(0) 配合opacity的話仍是會產生迴流的,而只用visibility 就只會產生重繪不會迴流

而  opacity 加上 transform: translateZ/3d  這個屬性以後便不會發生迴流和重繪了

3:不要使用 js 代碼對dom 元素設置多條樣式,選擇用一個 className 代替之。

4:若是確實須要用 js 對 dom 設置多條樣式那麼能夠將這個dom 先隱藏,而後再對其設置

5:不要在循環內獲取dom 的樣式例如:offsetWidth, offsetHeight, clientWidth, clientHeight... 這些。瀏覽器有一個迴流的緩衝機制,即多個迴流會保存在一個棧裏面,當這個棧滿了瀏覽器便會一次性觸發全部樣式的更改且刷新這個棧。可是若是你屢次獲取這些元素的實際樣式,瀏覽器爲了給你一個準確的答案便會不停刷新這個緩衝棧,致使頁面迴流增長。

因此爲了不這個問題,應該用一個變量保存在循環體外。

6:不要使用table 佈局,由於table 的每個行甚至每個單元格的樣式更新都會致使整個table 從新佈局

7:動畫的速度按照業務按需決定

8:對於頻繁變化的元素應該爲其加一個 transform 屬性,對於視頻使用video 標籤

9:必要時能夠開啓 GPU 加速,可是不能濫用

相關文章
相關標籤/搜索