避免繪圖是達成流暢的畫面更新率的關鍵,特別是在行動裝置上。不過,有時油漆會出現在最不尋常的地方。本文將探討 GIF 動畫為何可能導致不必要的繪圖作業,並提供簡單的修正方式。
層層疊疊的可愛
您可能知道,現代瀏覽器可能會將一組 DOM 元素繪製為個別的「圖片」,稱為圖層。有時整個網頁只有一個圖層,有時則有數百個,甚至在少數情況下有數千個!
當 DOM 元素組合成一個圖層,其中一個元素的視覺效果發生變化時,我們最終不僅要繪製變更的元素,還要繪製圖層中與變更元素重疊的所有其他元素。在某個圖層上繪製圖案時,覆蓋的像素會永久「遺失」,如果您想找回原始像素,就必須重新繪製。
因此,有時我們會將某個元素與其他元素分開,這樣在繪製時,我們就不需要重新繪製「未」變更的其他元素。舉例來說,如果您將固定的網頁標頭與可捲動的內容結合,每次捲動內容時,您都必須重新繪製標頭和新顯示的內容。將標頭放在個別圖層中,瀏覽器就能最佳化捲動功能。捲動時,瀏覽器可以移動圖層 (可能會使用 GPU 的協助),並避免重繪任何圖層。
每增加一個圖層,記憶體用量和效能開銷就會增加,因此目標是盡可能將網頁分組為較少的圖層,同時維持良好的效能。
這一切與 GIF 動畫有何關聯?
我們來看看這張圖片:

這是簡單應用程式的潛在圖層設定。此處有四個圖層:其中三個 (圖層 2 到 4) 是介面元素;後方圖層是載入器,剛好是動畫 GIF。在一般流程中,您會在應用程式載入時顯示載入器 (第 1 層),然後在所有作業完成後顯示其他層。但重點是:你必須隱藏動畫 GIF。
但為什麼我需要隱藏它?
好問題!在理想情況下,瀏覽器會自動檢查 GIF 的顯示狀態,並避免自動繪製。很遺憾,檢查動畫 GIF 是否會在畫面上遮蔽或顯示,通常比單純繪製動畫 GIF 的運算成本更高,因此會繪製動畫 GIF。
在最佳情況下,GIF 會位於其專屬的圖層,瀏覽器只需將其繪製並上傳至 GPU。但在最糟的情況下,所有元素都可能會被分組至單一圖層,瀏覽器就必須重新繪製每個元素。完成後,它仍需要將所有內容上傳至 GPU。即使使用者根本看不到 GIF,系統仍會為每個 GIF 影格執行上述所有工作。
在電腦上,您可能可以使用這種繪圖行為,因為 CPU 和 GPU 效能更強大,且兩者之間有充足的頻寬可用於傳輸資料。不過,在行動裝置上,繪圖的成本非常高,因此請務必謹慎使用。
這項異動會影響哪些瀏覽器?
如同往常,不同瀏覽器的行為有所差異。目前 Chrome、Safari 和 Opera 都會重新繪製,即使 GIF 已模糊處理也一樣。另一方面,Firefox 會判斷 GIF 已模糊處理,因此不需要重新繪製。Internet Explorer 仍是個黑盒子,即使在 IE11 中,由於 F12 工具仍在開發中,因此無法得知是否有重繪作業。
如何判斷是否有這個問題?
最簡單的方法是在 Chrome 開發人員工具中使用「Show paint rectangles」(顯示繪圖矩形)。載入「DevTools」,然後按下右下角的齒輪圖示 (),並選擇「Rendering」部分下方的「Show paint rectangles」。

你只需要尋找如下所示的紅色矩形:

畫面上的紅色小方塊表示 Chrome 正在重新繪製某些內容。您知道其他元素後面隱藏著載入器 GIF,因此當您看到如下所示的紅色方塊時,請隱藏可見的元素,並確認是否已讓動畫 GIF 旋轉。如果您有,則需要彈出一些 CSS 或 JavaScript,將 display: none
或 visibility: hidden
套用至該元素或其父項元素。當然,如果只是背景圖片,那麼請務必移除。
如要查看實際網站中的這項行為,請參考 Allegro,每張產品圖片都會顯示載入器 GIF,但會遮蔽而非明確隱藏。
結論
要達到 60fps,就只執行轉譯網頁所需的作業,移除多餘的繪圖是達成此目標的關鍵步驟。繼續執行的 GIF 動畫可能會觸發不必要的繪製作業,您可以使用 DevTools 的「Show paint rectangles」工具,輕鬆找出並偵錯這些不必要的繪製作業。
你不會讓動畫小貓載入器 GIF 永遠執行,對吧?