為什麼有些動畫速度緩慢?

新式瀏覽器能以低成本為兩個 CSS 屬性建立動畫:transformopacity。為其他內容建立動畫時,很可能就不太可能達到每秒 60 個影格 (FPS) 的流暢感。這篇文章說明原因。

動畫效能和畫面更新率

許多人都認為,為網路上的任何內容製作動畫時,會將 60 FPS 的畫面更新率設為 60 FPS。 這個畫面更新率可確保動畫順暢呈現。在網路上,影格是指完成更新及重新繪製畫面所需的一切工作時間。如果每個影格未能在 16.7 毫秒 (1000ms / 60 incognito 16.7) 完成,使用者就會察覺延遲。

轉譯管道

如要在網頁上顯示內容,瀏覽器必須執行下列依序步驟:

  1. 樣式:計算套用至元素的樣式。
  2. 版面配置:產生每個元素的幾何圖形和位置。
  3. 色調:將每個元素的像素填滿圖層
  4. 複合元素:在螢幕上繪製圖層。

這四個步驟稱為瀏覽器的「轉譯管道」

當您在已載入這些步驟的頁面中建立動畫時,必須再次發生。這個過程是從需要變更的步驟開始,讓動畫能夠發生。

如前所述,這些步驟會依序。舉例來說,如果您為會變更版面配置的項目建立動畫,繪製和複合步驟也必須再次執行。因此,比起只變更組合內容的動畫效果,為變更版面配置的內容製作動畫需要耗費較多成本。

建立版面配置屬性動畫

版面配置變更會計算受此變更影響的所有元素的幾何圖形 (位置和大小)。如果您變更一個元素,可能就需要重新計算其他元素的幾何圖形。舉例來說,如果您變更 <html> 元素的寬度,可能會影響其任何子項的寬度。由於元素會溢位並影響另一個元素,所以在樹狀結構較下方進行的變更,有時可能會導致版面配置一直回到頂端。

可見元素的樹狀結構越大,執行版面配置計算所需的時間就越長。

為繪製屬性建立動畫效果

「Paint」是一項程序,可讓您決定在畫面上繪製哪些順序元素。通常是管道中所有工作最長執行的時間。

大部分新版瀏覽器中的繪製作業是在軟體光柵化工具中完成。視應用程式中元素分成不同層的方式而定,除了變更的元素外,其他元素可能也需要繪製。

為複合屬性建立動畫效果

合成是指將頁面分割為圖層的過程,將頁面外觀轉換為像素 (光柵化),以及將圖層組合在一起來建立頁面 (合成) 的程序。

這就是為什麼 opacity 屬性會併入費用較低的動畫項目清單中。只要這個屬性位於其本身的層,GPU 就能在合成步驟中處理對屬性所做的變更。Chromium 瀏覽器和 WebKit 會為 opacity 上有 CSS 轉換或動畫的任何元素建立新圖層。

什麼是圖層?

將要添加動畫效果或會轉換到新圖層的項目放在新圖層上,瀏覽器只需要重新繪製這些項目,其他項目則不需要。你或許已經熟悉 Photoshop 的圖層概念,這個圖層可以同時移動多項元素。瀏覽器算繪圖層的概念與前述概念相似。

雖然瀏覽器會擅長判斷新層應包含哪些元素,但如果遺漏任何元素,也可以選擇強制建立圖層。相關資訊請見「如何建立高效能動畫」。不過,由於每個圖層都會使用記憶體,因此建立新圖層時應格外謹慎。在記憶體有限的裝置上建立新層,可能會導致效能問題比您要解決的效能問題更嚴重。此外,每一層的紋理都必須上傳至 GPU。因此,CPU 和 GPU 之間的頻寬限制可能會相當有限。

CSS 與 JavaScript 的成效

你可能會想知道:從效能的角度來看,使用 CSS 或 JavaScript 製作動畫的效果是否更好?

CSS 動畫和網頁動畫 (在支援 API 的瀏覽器中) 通常會在名為合成器執行緒的執行緒上處理。這與瀏覽器的「主執行緒」不同,在執行樣式、版面配置、繪製和 JavaScript 的情況下。也就是說,如果瀏覽器在主執行緒上執行一些昂貴的工作,這些動畫可以持續進行,而不會中斷。

如本文所述,在許多情況下,其他轉換和不透明度的變更也可由合成器執行緒處理。

如果有任何動畫觸發了繪製和/或版面配置的觸發事件,則需要主要執行緒執行工作。CSS 和 JavaScript 動畫都是如此,而版面配置或繪製作業的負擔,可能會使與 CSS 或 JavaScript 執行有關的任何工作混淆,以呈現問題表情符號。