如何優化像素管道的 Paint 和 Composite?

更詳細探討如何優化像素管道(Browser Rendering Pipeline)的繪製(Paint)和合成(Composite)這兩個階段。

Browser Rendering Pipeline

圖片來源:Rendering Performance

繪製(Paint)

Paint Flashing

若想知道繪製(Paint)發生於何時何處,可使用 Chrome DevTools > More tools > Rendering > 勾選 Paint flashing,開啟後檢視畫面,發生繪製時該區塊會閃綠光。

範例如下圖,scroll 這個網站,閃綠光的地方就是當下發生繪製之處。

Paint flashing

每次繪製的區塊原來有這麼大!該縮小繪製區域了。

Paint Profiler

若想知道繪製細節,可使用 Paint Profiler 這個工具,Paint Profiler 位於 Chrome DevTools > More tools > Layers,點某一圖層後,在 Details 上會顯示 Paint Profiler 連結,點進去就會看到了。

Layers Details

點進去就看到 Paint Profiler,呈現繪製階段所有的細節。

Paint Profiler

這些細節可作為簡化繪製複雜度的改進建議,範例

合成(Composite)

在 Chrome DevTools Timeline 的紀錄中,有兩種是和 Composite 相關的

圖層數太多嗎?該降低圖層數了。

如何提升繪製會和合成的效能?

升階可提升繪製的效能,而圖層數關乎合成的效能,因此這是「減少繪製區域」和「增加圖層數」的取捨。圖層數愈多,就需要花愈多時間在圖層的管理和合成上,但可換得減少繪製區域的好處;圖層數愈少,雖然花在圖層管理和合成的時間較少,但繪製區域範圍較大、較花時間。

範例-概念說明

開發者通常不干涉圖層的管理,基本上都交由瀏覽器自動處理,但若為了減少繪製的區域,就會考慮把某些元素提升到另一個圖層,意即升階,有什麼需要更新的,就處理這一塊就好。

範例如下,這是一個手機版網站,左側是側邊欄,右側上方有一個小的導航列(含漢堡選單和標題),右側下方是文章列區塊。

試著說明哪些元素要放到同一個圖層?針對要放在同一個圖層的元素,標記同一個數字。

哪些元素要放到同一個圖層

圖片來源:Browser Rendering Optimization: Compositing and Painting

防雷-第一次… ヽ(∀ ゚ )人(゚ ∀ ゚)人( ゚ ∀)人(∀ ゚ )人(゚ ∀ ゚)人( ゚ ∀)ノ

防雷-第二次… ヽ(∀ ゚ )人(゚ ∀ ゚)人( ゚ ∀)人(∀ ゚ )人(゚ ∀ ゚)人( ゚ ∀)ノ

防雷-最後提醒… ヽ(∀ ゚ )人(゚ ∀ ゚)人( ゚ ∀)人(∀ ゚ )人(゚ ∀ ゚)人( ゚ ∀)ノ

答案。

哪些元素要放到同一個圖層-解答

Layers

若想知道目前頁面上有多少圖層、產生圖層的原因,可使用 Chrome DevTools > More tools > Layers,可用此控管圖層數目。

Layers Details

左邊的側邊欄顯示有多少圖層和所屬 DOM Element,右上可針對此圖層旋轉或指定圖層,指定後可在右下看 Details 和 Profiler。Details 上的 Compositing Reasons 會顯示產生圖層的原因。

Layout Borders

既然想把元素分圖層管理,那就要先確認想要放在同一層的元素是否擁有自己的圖層。

使用工具 Layout borders 來檢視頁面上的圖層狀態,Layout borders 位於 Chrome DevTools > Rendering > Layout borders,開啟後會看到頁面顯示網格,淺藍色的線表示瀏覽器自行將圖層切割的狀況,橘框表示元素所在的圖層。

Layout Borders

will-change

如果想要放在同一個圖層的元素沒有自己的圖層,就提升它們到另一個圖層。建立新圖層的方式,即是在該元素使用 will-change: transform 或舊瀏覽器可用密技(hack) transform: translateZ(0)will-change 會提示瀏覽器有視覺上的更動,然後將這些元素放到一個新的合成圖層上,這樣就可以減少繪製的區域,這對於 opacity 或移動效果特別有用。

.layer {
  will-change: transform;
  transform: translateZ(0);
}

will-changetranslateZ(0) 的差異在於

注意,不要為了提升效能,在所有元素都加上 will-change,因為這會增加記憶體的使用和花更多時間在合成階段上,導致效能不佳,這在手機上尤其明顯。

範例

點此看範例網站。

若要升階元素 .box,CSS 要怎麼寫呢?

解答。

答案是在 .box 加入 will-change: transform

範例-找出產生新圖層的原因?

點此看範例網站,打開 Layers 後點選 section#background 這個圖層。

同上圖,由於 #background 這個元素使用 CSS 3D transform,因此產生新圖層。若拿掉這指令就不會產生新的圖層了。

找出產生新圖層的原因?

參考資料


效能調校 轉譯效能 關鍵轉譯路徑 Rendering Performance Critical Rendering Path Chrome DevTools will-change css css3 animations 前端效能 系列文