CSS3 Animation

使用 CSS3 Transition 和 Animation 製作動畫、效能優化。

CSS3 製作動畫的方式有 2 種

以下分別述之。

Transition 漸變

Transition 讓物件能在特定時間內流暢地執行一連串動作,而非生硬地突然改變。

語法

使用 Transition 最重要的就是指出想要改變的屬性(Property)和時間(Duration)。

transition: property duration timing-function delay;

Browser Support

Chrome 26+、Firefox 16+、IE 10+、Safari 6.1+、Opera 12.1+,基本上所有主流瀏覽器皆支援。

範例 1

小方塊的寬度在一秒內由 100px 變成 200px,看起來就像是向右延伸了 100px。

Transition 範例

程式碼。

.cube {
  width: 100px;
  height: 100px;
  background: #41d2f2;
  transition: width 1s;
  &.move {
    width: 200px;
  }
}

原始碼

範例 2

小方塊向右移動 200px,並且旋轉 360 度。

Transition 範例

程式碼。

.cube {
  width: 100px;
  height: 100px;
  background: #41d2f2;
  transition: transform 1s;
  &.move {
    transform: translate3d(200px, 0, 0) rotate(360deg);
  }
}

原始碼

範例:translate3d

同上,利用一個藍色的小方塊 cube 作範例,這個小方塊被放在一個虛線包圍的 container 裡面。

translate3d 範例

原始碼

Animation 動畫

Animation 讓 HTML 元件在不使用 JavaScript 或 Flash 的情況下有動畫效果。

語法

animation: name duration timing-function delay iteration-count direction fill-mode play-state;
@keyframes animationName {
  keyframes-selector {
    /* css-styles */
  }
}

Browser Support

Chrome 43+、Firefox 16+、IE 10+、Safari 9+、Opera 30+,也是所有主流瀏覽器皆支援。

範例 3

改寫上面的範例 2。指定執行動畫 move,總時間為 2 秒,執行無數次。

Animation 範例

程式碼。

.cube {
  width: 100px;
  height: 100px;
  background: #41d2f2;
  animation: move 2s infinite;
}

@keyframes move {
  0% {
    transform: translate3d(0, 0, 0) rotate(0deg);
  }
  50% {
    transform: translate3d(200px, 0, 0) rotate(360deg);
  }
  100% {
    transform: translate3d(0, 0, 0) rotate(0deg);
  }
}

原始碼

Transition vs Animation

效能優化

目前大多數的裝置都是以每秒 60 次的頻率重新整理螢幕,因此瀏覽器需要儘量滿足裝置的重新整理頻率來重組畫面,讓使用者能順暢地與畫面互動。而每秒 60 次的重整意味著每次重整只有 1 / 60 秒 ~ 16.67 ms 的時間,扣除例行任務,每次重整可能只有 10 ms 的時間。若超過這個時間,就會發生閃避。為了達成這個效果,就必須優化關鍵轉譯路徑(Critical Rendering Path)

關鍵轉譯路徑(Critical Rendering Path)

瀏覽器在經過一連串的工作後會呈現一個初始畫面,而這一連串的工作歷程就是指 Critical Rendering Path。因此,優化 Critical Rendering Path 就是優化網頁效能的關鍵。這歷程會有以下的步驟:

像素管道

圖片來源:Rendering Performance

畫面的變更會透過 Layout、Paint 和 Composite 三階段完成,但並非每個階段都需要經歷,需視使用的指令而定。因此可能是

由以上可知,一旦變更某個步驟,便會從這個步驟開始重繪。所以,樣式的變更儘量位於後面的階段,這樣花費的成本可降至最低-某些功能就可利用只影響「Composite」這一層的指令來完成,這樣只要重繪最後一個階段就好了。例如

點此看實際範例。

這在動畫處理或捲動畫面時尤其重要。想知道 CSS 指令會影響的層面,可參考-CSS Triggers

[備註] Web Engine

優化動畫效能,達到 60fps!

以下修改方式出自-Smooth as Butter: Achieving 60 FPS Animations with CSS3。在這裡使用一個簡單的範例,類似手機版網站,點擊 icon 後由左滑出選單。

範例 4:修改前

如下所示,由於改變的是 left 屬性,因此會重繪 layout,使得動畫不夠流暢。

Animation 範例

程式碼。

.app-menu {
  left: -300px;
  transition: left 300ms;
}

.app-menu-open {
  left: 0;
}

原始碼

Chrome DevTool Timeline 如下,綠色的部份即 FPS,FPS 愈低表示能以 60 FPS 渲染畫面,或使用 FPS meter 檢視畫面更新頻率。

Animation 範例

FPS 不夠規律,效能有待改善。

範例 5:改用 transform 位移

改用只影響 Composite 這階段的指令 transform: translateX(n) 來完成。

程式碼。

.app-menu {
  transform: translateX(-100%);
  transition: transform 300ms;
}

.app-menu-open {
  transform: none;
}

原始碼

Chrome DevTool Timeline。

Animation 範例

FPS 規律,改善些許效能,動畫較流暢。關於 Composite 這階段的指令對效能的影響,可參考-Stick to Compositor-Only Properties and Manage Layer Count

範例 6:觸發 GPU 繪製

利用特定 CSS 樣式強制觸發瀏覽器使用 GPU 繪製畫面。

程式碼。

.app-menu {
  transform: translate3d(-100%, 0, 0);
  transition: transform 300ms;
}

.app-menu-open {
  transform: none;
}

原始碼

Chrome DevTool Timeline。

Animation 範例

FPS 規律,較範例 4 改善了一點點效能。

或使用 will-change,推薦閱讀-使用 CSS3 will-change 提高頁面滾動、動畫等渲染性能

範例 7:改變 layout

改變版面配置,試圖讓影響範圍變小。

程式碼。

<div class="menu">
  <div class="app-menu"></div>
</div>
<div class="layout">
  <div class="header">
    <div class="menu-icon"></div>
  </div>
</div>

原始碼

Chrome DevTool Timeline。

Animation 範例

FPS 規律,較範例 4 改善了一點點效能。

與原作者的實驗結果比較,大概都會比未修改前的效能改善一些,但並未如原作者的範例那樣大幅改進,可能是因為現今使用的電腦設備都十分地好吧。關於版面配置對效能的影響,可參考- Avoid Large, Complex Layouts and Layout Thrashing

動畫設定注意事項

References

後記

(2018/07/15 更新)

本文對於效能改善方法與範例和如何使用工具檢視並無深入的描述(甚至有誤,因而稍做修改與更正,歡迎指教),因此我又整理了一篇文章-關鍵轉譯路徑 Critical Rendering Path,除了對 Browser Rendering Pipeline 的每個步驟有更詳細的說明外,也包含使用 Chrome DevTools 檢測效能、實際優化範例。


css3 animations will-change Critical Rendering Path 關鍵轉譯路徑 效能調校 轉譯效能 Rendering Performance Chrome DevTools css