CSS 繪製時間和網頁轉譯權重

Colt McAnlis
Colt McAnlis

簡介

如果您是會持續關注「瀏覽器運作方式」這類資訊的人,那麼您可能已經知道,最近有幾篇精彩的文章詳細介紹 Chrome 的 GPU 加速轉譯器/合成作業。首先,Chrome 中的加速轉譯:圖層模型一文提供了 Chrome 如何使用圖層概念繪製網頁的簡介;如要深入瞭解相關資訊,請參閱 Chrome 中的 GPU 加速合成一文,瞭解 Chrome 如何使用這些圖層和 GPU 來轉譯網頁。

哲學問題

我花了大量時間為 3D 目的編寫軟體算繪器,因此我認為,在繪製網頁時,某些 CSS 屬性應具有不同的效能。舉例來說,將小圖片算繪至螢幕上,與在任意形狀上繪製陰影的演算法作業完全不同。因此問題變成:不同的 CSS 屬性如何影響網頁的算繪權重?

我的目標是根據著色時間,將大量 CSS 屬性/值分類,以便瞭解哪些 CSS 屬性類型比其他類型更有效率。為此,我使用膠帶和泡泡糖編寫了一些自動化程式,嘗試在 CSS 繪製時間中加入數值可見度,運作方式如下:

  • 產生一系列個別的 HTML 網頁,每個網頁都含有單一 DOM 元素,並附加一些 CSS 屬性變化。
  • 執行自動化動作指令碼,針對每個網頁執行以下動作:
  • 請查看所有時間,並驚嘆這些數字。(這部分很重要…)

透過這種設定,我們會產生一系列 HTML 頁面,每個頁面都包含 CSS 屬性和值的獨特排列組合;舉例來說,以下是兩個 HTML 檔案:

<style>
#example1 {
    background: url(foo.png) top left / 50% 60%;
    padding: 20px; 
    margin-top: 10px;
    margin-right: 20px; 
    text-align: center;
}
</style>
<div id="example1">WOAH</div>

另一個更複雜的

<style>
#example1 {
    background-color:#eee;
    box-shadow: 1px 2px 3px 4px black;
    border-radius: 50%;
    background: radial-gradient(circle closest-corner, white, black);
    padding: 20px; 
    margin-top: 10px;
    margin-right: 20px; 
    text-align: center;
}
</style>
<div id="example1">WOAH</div>

以下是上一個範例的變化版本,我們只會變更 radial-gradient 值:

<style>
#example1 
{
    background-color:#eee;
    box-shadow: 1px 2px 3px 4px black;
    border-radius: 50%;
    background: radial-gradient(farthest-side, white, black);
    padding: 20px; 
    margin-top: 10px;
    margin-right: 20px; 
    text-align: center;
}
</style>
<div id="example1" style="padding: 20px; margin-top: 10px;margin-right: 20px; text-align: center;">WOAH</div>

然後將每個網頁載入 全新的 Chrome 例項 (以確保時間點不會受到網頁重新載入時任何舊版狀態的影響),並使用 Skia Picture (*.SKP) 評估用於繪製網頁的 Skia 指令。為每個 HTML 檔案產生 SKP 檔案後,我們會執行另一個批次,透過 Skia Benchmark 應用程式 (由 Skia 原始碼建構) 推送 *.SKP 檔案,並記錄轉譯該網頁所需的平均時間。

評估資料

從這項資訊,我們現在可以粗略繪製一組 CSS 屬性所需的繪製時間。或者,我們可以開始依 CSS 資源的繪製成效進行排序。以下是使用 Chrome 27 開發人員版本繪製的大型圖表,顯示此程序的所有完整時間資料。請注意,隨著 Chrome 速度越來越快,所有資料都可能會有所變動。

測試中所有排列組合所需的時間

每個垂直長條代表網頁的繪製時間,其中包含單一 CSS 屬性組合 (放大 100 倍;此圖表的真實比例值為 0.1.56 毫秒)。雖然有許多漂亮的線條,但在這種形式下,這些線條幾乎沒有用處;我們需要進行一些資料挖掘,才能找出有用的趨勢。

首先,我們發現某些 CSS 屬性比其他屬性更耗費渲染時間。舉例來說,在 DOM 元素上繪製陰影需要使用多重迴圈運算,並搭配樣條曲線和其他不便處理的項目,而這與不透明度相比,應更容易算繪。

繪製僅含 1 個 CSS 屬性的元素所需的時間

其次,更有趣的是,CSS 屬性組合所需的繪製時間,可能比各個部分的總和還要長。從觀察者的角度來看,這有點奇怪,因為我們預期 A + B = C,而不是 2.2C。例如新增 box-shadowborder-radius-stroke

測試中所有排列組合所需的時間

這裡最有趣的地方在於,這並非只是 box-shadow 屬性本身,而是特定值的排列組合舉例來說,下方顯示 box-shadow : 50%border-radius 的值變化組合。

測試中所有排列組合所需的時間

根據資料顯示,這項問題會持續一段時間。有很多奇怪的組合,我的測試套件幾乎不會觸及這些組合;但仍有許多測試和組合可能會產生有趣的結果

找出網頁的算繪權重

開發人員可以追蹤網頁上每個元素的算繪時間,進而評估網頁算繪重量,以及這項重量對網站回應速度的影響。以下提供幾個開始評估的訣竅。

  1. 在 Chrome 開發人員工具中使用 Chrome 的連續繪圖模式,瞭解哪些 CSS 屬性會造成效能損失。
  2. 將 CSS 審查納入現有的程式碼審查程序,以便找出效能問題。請找出 CSS 中使用較耗資源的項目,例如漸層和陰影。請問自己是否真的需要這些內容?
  3. 如有疑問,請一律選擇效能較佳的選項。使用者可能不會記得欄位邊框的寬度,但他們會記得造訪網站時的感受。

結語

這項實驗最有趣的地方在於,Chrome 版本會持續變更時間,希望速度能越來越快;瀏覽器軟體是不斷變化的表面區域。今天速度緩慢的網站,明天可能就會變得快速。您可以從這篇文章中移除,避免將 box-shadow: 1px 2px 3px 4px 放在已含有 border-radius:5 的元素中。不過,更有價值的結論應該是 CSS 屬性會直接影響網頁繪製時間。

參考資料