簡介
如果您是那種會持續關注瀏覽器運作方式等資訊的人,那麼您可能已經知道最近有一些很棒的文章,詳細介紹了 Chrome 的 GPU 加速渲染器/複合操作。首先,Chrome 中的加速轉譯:圖層模型是 Chrome 如何使用圖層概念繪製網頁的絕佳簡介;如需深入瞭解 Chrome 中的 GPU 加速合成,請參閱 Chrome 如何使用這些圖層,以及 GPU 轉譯網頁。
哲學問題
我花了很多時間編寫 3D 軟體光柵化器,因此我認為某些 CSS 屬性在繪製網頁時,應該會有不同的效能。舉例來說,將小型圖片光柵化至螢幕,與在任意形狀上繪製投射陰影,是完全不同的演算法運算。因此,問題就變成:不同的 CSS 屬性如何影響網頁的算繪權重?
我的目標是根據繪製時間將大量 CSS 屬性/值分類,以便瞭解哪些類型的 CSS 屬性效能優於其他屬性。為此,我用 duct-tape 和 bubble gum 寫了一些自動化功能,嘗試為 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 圖片 (*.SKP),評估用於繪製網頁的 Skia 指令。為每個 HTML 檔案產生 SKP 檔案後,我們會執行另一批作業,透過 Skia 基準測試應用程式 (以 Skia 原始碼建構) 推送 *.SKP 檔案,該應用程式會傾印轉譯該網頁所需的平均時間。
評估資料
現在,我們大致可以繪製一組 CSS 屬性需要多少時間繪製。或者,我們可以開始根據 CSS 屬性的繪製效能,對其進行堆疊排名。以下是使用 Chrome 27 Beta 版擷取的大型圖表,顯示這項程序的所有時間資料。請注意,隨著 Chrome 速度越來越快,所有資料都可能隨時變動。
每個垂直長條代表單一 CSS 屬性組合的網頁繪製時間 (放大 100 倍;這張圖表的真實比例值為 0、1.56 毫秒)。雖然有許多漂亮的線條,但這種形式沒什麼用處;我們需要進行一些資料探勘,找出有用的趨勢。
首先,我們發現某些 CSS 屬性的轉譯成本明顯高於其他屬性。舉例來說,在 DOM 元素上繪製投射陰影時,需要使用曲線和其他複雜元素進行多階段作業,而透明度則較容易算繪。
其次,更有趣的是,CSS 屬性組合的繪製時間可能比各部分總和更長。從觀察者的角度來看,這有點奇怪,我們預期 A+B = C,而不是 2.2C。例如,新增 box-shadow 和 border-radius-stroke:
這項功能最有趣的地方在於,它不只是 box-shadow 屬性本身,而是特定值的排列組合。舉例來說,下方顯示 box-shadow : 50% 和 border-radius 的分組,其中包含值變化。
從資料來看,這種情況會持續一段時間。有許多奇怪的組合,我的測試套件幾乎無法涵蓋所有組合;還有許多測試和組合可能會產生有趣的結果
查看網頁轉譯權重
開發人員可以追蹤網頁上每個元素的轉譯時間,開始評估網頁轉譯權重,以及這對網站回應速度的影響。以下提供幾個入門訣竅
- 在 Chrome 開發人員工具中使用 Chrome 的連續繪製模式,瞭解 CSS 屬性會耗費多少資源。
- 將 CSS 審查納入現有的程式碼審查流程,找出效能問題 在 CSS 中找出使用已知較耗費資源的項目 (例如漸層和陰影) 的地方。請思考:我真的需要這些嗎?
- 如有疑慮,請一律以提升效能為優先。使用者可能不會記得欄的邊框間距寬度,但會記得造訪網站時的感受。
結論
這項實驗最有趣的地方在於,時間會隨著每個 Chrome 版本持續變化 (希望速度會越來越快),瀏覽器軟體是個不斷變化的介面。今天速度慢,明天可能就變快。您可以從這篇文章中學到,避免將 box-shadow: 1px 2px 3px 4px 放在已有 border-radius:5 的元素上。不過,更重要的結論是 CSS 屬性會直接影響網頁繪製時間。