如何建立高效能 CSS 動畫

本指南說明如何建立高效能的 CSS 動畫。

如要瞭解這些建議背後的理論,請參閱「為什麼部分動畫會變慢?」一文。

瀏覽器相容性

本指南建議的所有 CSS 屬性都支援跨瀏覽器。

transform

Browser Support

  • Chrome: 36.
  • Edge: 12.
  • Firefox: 16.
  • Safari: 9.

Source

opacity

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 2.

Source

will-change

Browser Support

  • Chrome: 36.
  • Edge: 79.
  • Firefox: 36.
  • Safari: 9.1.

Source

移動元素

如要移動元素,請使用 transform 屬性的 translaterotation 關鍵字值。

舉例來說,如要將項目滑入檢視畫面,請使用 translate

.animate {
  animation: slide-in 0.7s both;
}

@keyframes slide-in {
  0% {
    transform: translateY(-1000px);
  }
  100% {
    transform: translateY(0);
  }
}

使用 rotate 旋轉元素。以下範例會將元素旋轉 360 度。

.animate {
  animation: rotate 0.7s ease-in-out both;
}

@keyframes rotate {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

調整元素大小

如要調整元素大小,請使用 transform 屬性的 scale 關鍵字值。

.animate {
  animation: scale 1.5s both;
}

@keyframes scale {
  50% {
    transform: scale(0.5);
  }
  100% {
    transform: scale(1);
  }
}

變更元素的顯示設定

如要顯示或隱藏元素,請使用 opacity

.animate {
  animation: opacity 2.5s both;
}

@keyframes opacity {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

避免觸發版面配置或繪製的屬性

使用任何 CSS 屬性進行動畫製作前 (transformopacity 除外),請先判斷該屬性對算繪管道的影響。除非絕對必要,否則請避免觸發版面配置或繪製的任何屬性。

強制建立圖層

如「為什麼部分動畫會變慢?」一文所述,將元素放在新圖層上,瀏覽器就能重新繪製這些元素,而不必重新繪製其餘版面配置。

瀏覽器通常可以妥善決定應將哪些項目放在新圖層上,但您可以使用 will-change 屬性手動強制建立圖層。顧名思義,這項屬性會告知瀏覽器這個元素即將以某種方式變更。

在 CSS 中,你可以將 will-change 套用至任何選取器:

body > .sidebar {
  will-change: transform;
}

不過,規格建議您只將此屬性新增至即將變更的元素。舉例來說,這可用於使用者可滑入和滑出的側邊欄。如果元素不常變更,請在可能發生變更時,使用 JavaScript 套用 will-change。請務必給瀏覽器足夠的時間執行必要的最佳化作業,並在變更停止時移除資源。

如要在不支援 will-change 的瀏覽器中強制建立圖層,可以設定 transform: translateZ(0)

偵錯動畫緩慢或有故障的問題

Chrome 開發人員工具和 Firefox 開發人員工具可協助您找出動畫緩慢或有問題的原因。

檢查動畫是否會觸發版面配置

如果動畫使用 transform 以外的項目移動元素,可能會很慢。以下範例比較使用 transform 的動畫與使用 topleft 的動畫。

錯誤做法
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     top: calc(90vh - 160px);
     left: calc(90vw - 200px);
  }
}
正確做法
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     transform: translate(calc(90vw - 200px), calc(90vh - 160px));
  }
}

您可以在下列兩個範例中測試這項功能,並使用開發人員工具探索成效。

Chrome 開發人員工具

  1. 開啟「成效」面板。
  2. 在動畫播放時記錄執行階段效能
  3. 檢查「摘要」分頁。

如果「摘要」分頁的「算繪」值不為零,可能表示動畫會導致瀏覽器執行版面配置作業。

「摘要」面板顯示轉譯時間為 37 毫秒,繪製時間為 79 毫秒。
animation-with-top-left 範例會導致轉譯工作。
「摘要」面板顯示的轉譯和繪製值為零。
animation-with-transform 範例不會導致轉譯工作。

Firefox 開發人員工具

在 Firefox 開發人員工具中,瀑布圖可協助您瞭解瀏覽器花費時間的位置。

  1. 開啟「成效」面板。
  2. 在動畫播放時開始記錄效能。
  3. 停止錄製,然後檢查「瀑布圖」分頁。

如果看到「Recalculate Style」項目,表示瀏覽器必須返回算繪瀑布圖的開頭,才能算繪動畫。

檢查是否有影格遺失

  1. 在 Chrome 開發人員工具中開啟「算繪」分頁
  2. 勾選「FPS meter」(每秒影格數計量表) 核取方塊。
  3. 在動畫執行時觀察這些值。

請注意 FPS 計量表 UI 頂端的「影格」標籤。 顯示的值類似 50% 1 (938 m) dropped of 1878。高效能動畫的百分比很高,例如 99%,表示很少影格遭到捨棄,動畫看起來很流暢。

FPS 計量器顯示有 50% 的影格遭到捨棄
animation-with-top-left 範例會導致 50% 的影格遭到捨棄
FPS 計量器只顯示 1% 的影格遭到捨棄
animation-with-transform 範例只會導致 1% 的影格遭到捨棄。

檢查動畫是否會觸發繪製

有些屬性會比其他屬性更耗費瀏覽器資源來繪製。舉例來說,凡是涉及模糊效果 (例如陰影) 的項目,繪製時間都會比繪製紅色方塊更長。這些差異不一定會在 CSS 中顯示,但瀏覽器開發人員工具可協助您找出需要重新繪製的區域,以及其他與繪製相關的效能問題。

Chrome 開發人員工具

  1. 在 Chrome 開發人員工具中開啟「算繪」分頁
  2. 選取「繪製閃爍效果」
  3. 在畫面上移動指標。
以綠色醒目顯示的 UI 元素,表示該元素將重新繪製
在 Google 地圖的範例中,你可以看到重新繪製的元素。

如果看到整個螢幕閃爍,或有不應變更的區域遭到醒目顯示,請進一步調查。

如要判斷特定屬性是否導致繪製相關效能問題,可以使用 Chrome 開發人員工具中的繪製剖析器

Firefox 開發人員工具

  1. 開啟「設定」,然後新增「切換繪圖閃爍」的工具箱按鈕。
  2. 在要檢查的頁面上,切換按鈕開啟,然後移動滑鼠或捲動,即可查看醒目顯示的區域。

在合成階段製作動畫

請盡可能將動畫限制在 opacitytransform,讓動畫留在算繪路徑的合成階段。使用開發人員工具檢查路徑的哪個階段受到動畫影響。

使用繪圖剖析器,查看是否有任何繪圖作業特別耗用資源。如有發現任何問題,請檢查其他 CSS 屬性是否能提供相同的外觀和風格,但效能更佳。

請謹慎使用 will-change 屬性,只有在遇到效能問題時才使用。