CSS 動畫教學:從 @keyframes 到屬性設定的完整實作

本篇 CSS 動畫教學,詳細解析 @keyframes 核心語法與 animation 屬性設定,包含常用速度曲線、播放次數與方向控制。透過按鈕微互動、載入動畫等實例,教你輕鬆製作流暢的網頁動畫效果。

CSS動畫CSS Animation@keyframes網頁動畫教學前端動畫

CSS Animation 是什麼?用它能做哪些動畫?

CSS Animation 是一種純粹使用 CSS 屬性來定義與執行網頁動畫的技術,它能讓元素在不同狀態之間產生平滑的過渡效果。相較於 JavaScript 動畫,它的主要優勢在於性能表現優異,因為動畫的計算與執行由瀏覽器的合成器(Compositor)處理,能有效避開繁重的版面計算(Layout),流暢度通常更佳。此外,其宣告式的語法讓動畫的定義與樣式分離,便於維護與修改,開發者無需編寫複雜的 JS 邏輯就能實現許多互動效果。常見的應用場景包括:按鈕在懸停時的微交互反饋、頁面載入時的引導式動畫、滾動時觸發的元素淡入效果,以及用來吸引使用者視覺焦點的循環提示動畫。

核心語法解析:`@keyframes` 與基本結構

要建立一個可運行的 CSS 動畫,必須完成兩個核心步驟:首先使用 `@keyframes` 規則定義動畫序列,然後透過選擇器的 `animation` 相關屬性將其啟用。`@keyframes` 用於指定動畫中間狀態的關鍵影格,可以使用 `from`(等同 `0%`)與 `to`(等同 `100%`)來定義起始與結束,或使用百分比來設定多個中間狀態。接著,在目標元素的樣式規則中,必須透過 `animation-name` 屬性連結此 `@keyframes` 的名稱,並透過 `animation-duration` 設定動畫播放一次所需的時間長度,例如 `1s` 或 `500ms`。

/* 步驟一:定義關鍵影格 */
@keyframes slideIn {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

/* 步驟二:應用動畫至元素 */ .box { animation-name: slideIn; animation-duration: 0.8s; }

完整屬性參考表

除了基礎的名稱與時間,`animation-*` 系列屬性提供了豐富的控制選項,讓動畫行為更貼合需求。以下表格整理了主要屬性及其常用值,是實作時的重要速查參考。

屬性 作用 常用值範例 說明
animation-timing-function 控制動畫速度曲線 ease(預設), linear, ease-in, ease-out, ease-in-out, cubic-bezier(x1, y1, x2, y2) cubic-bezier 允許自訂貝茲曲線,前四個關鍵字是預設曲線的快捷方式。ease 是慢速開始、加速、再減速結束。
animation-iteration-count 設定動畫重複播放次數 1(預設), 2, infinite 設為 infinite 可製作循環動畫,常用於載入指示器或背景效果。
animation-direction 指定動畫播放方向 normal(預設), reverse, alternate, alternate-reverse alternate 會讓動畫在奇數次正向播放,偶數次反向播放,製作來回效果。
animation-fill-mode 設定動畫開始前與結束後的樣式套用方式 none(預設), forwards, backwards, both forwards 讓元素保持在最後關鍵影格的狀態。both 則包含了 forwards 與 backwards 的效果,在延遲期間就先套用第一個關鍵影格的樣式。
animation-delay 設定動畫開始前的等待時間 0s(預設), 0.5s 可用於錯開多個元素的動畫啟動時間,創造序列感。設定負值會讓動畫從中間開始播放。

動畫屬性速查:`animation` 簡寫

為了提升開發效率,可以使用 `animation` 簡寫屬性,將上述多個屬性合併至一行宣告中。其正確的語法順序為:`animation: 名稱 時間 速度曲線 延遲 重複次數 方向 填充模式`。務必留意,簡寫屬性中容易遺漏的順序問題,以及最後一個數值若為時間單位,可能會被誤判為 `animation-duration`。

/* 完整寫法 */
.box {
  animation-name: slideIn;
  animation-duration: 0.8s;
  animation-timing-function: ease;
  animation-delay: 0.2s;
  animation-fill-mode: both;
}

/* 使用簡寫屬性改寫 */ .box { animation: slideIn 0.8s ease 0.2s both; }

在這個簡寫中,第一個時間值(0.8s)被解析為 `animation-duration`,第二個時間值(如果有的話)才會被視為 `animation-delay`。`both` 作為 `animation-fill-mode` 的值,需要明確寫入,否則會套用預設值 `none`。

應用場景與實戰範例

將理論轉化為實際互動,是掌握 CSS Animation 的關鍵。以下提供兩個常見場景的實作範例,展示如何從基本屬性出發,建構出有用的網頁動效。

範例一:按鈕懸停縮放效果

當使用者遊標移至按鈕時,產生微妙的放大效果,能提供明確的互動反饋。此效果主要依賴 `transform` 屬性進行動畫,性能表現優良。

<button class="hover-btn">懸停我</button>
.hover-btn {
  padding: 0.8rem 1.5rem;
  background-color: #007bff;
  color: white;
  border: none;
  cursor: pointer;
  /* 確保過渡效果平滑 */
  transition: transform 0.2s ease;
}

.hover-btn:hover { transform: scale(1.05); }

範例二:元素進入視口的淡入動畫

結合 `animation-delay`,可以讓多個元素依序產生動畫,增加視覺層次。此範例假設已透過其他方式(如 JavaScript 的 Intersection Observer)為進入視口的元素添加了 `.animate-in` 類別。

<div class="fade-item">項目一</div>
<div class="fade-item">項目二</div>
<div class="fade-item">項目三</div>
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.fade-item { opacity: 0; /* 元素初始狀態為透明且偏移,準備好被動畫觸發 */ animation: fadeInUp 0.6s ease forwards; animation-delay: 0.2s; }

/* 為不同項目錯開動畫時間 */ .fade-item:nth-child(2) { animation-delay: 0.4s; } .fade-item:nth-child(3) { animation-delay: 0.6s; }

使用動畫庫(如 Animate.css)快速實現

若追求開發速度與豐富的現成效果,使用像 Animate.css 這類的 CSS 動畫函式庫是個高效選擇。這類庫預先定義了大量的 `@keyframes` 與對應的類別,開發者無需自行編寫動畫序列,只需透過 CDN 或本地引入檔案,再為目標元素添加指定的類別名稱即可套用效果。例如,引入 Animate.css 後,僅需添加 `class="animate__animated animate__fadeIn"` 即可獲得淡入動畫。

選擇使用原生 CSS Animation 或動畫庫,可基於以下考量:當動畫需要高度客製化、嚴格控制性能或專案要求零外部依賴時,原生 CSS 是更靈活的選擇。反之,若專案處於快速原型階段、需要多種常見效果且希望減少手動編碼時間,動畫庫能顯著提升開發效率。在 [網頁設計方法論](/posts/web-design-guide/) 的整體流程中,動畫是提升使用者體驗的環節之一,工具的選擇應服務於專案目標。

@keyframes 裡的 from/to 和百分比寫法有什麼不同?

from 和 to 分別是 0% 和 100% 的別名,僅適用於只有起始與結束狀態的簡單動畫。使用百分比可以定義多個中間關鍵影格,讓動畫過程更豐富,例如在 50% 處改變顏色,能實現更複雜的序列效果。

如何讓 CSS 動畫重複無限播放?

在 animation-iteration-count 屬性中設定值為 infinite 即可。常用於循環背景動畫、載入圖標旋轉或脈衝提示等需要持續運行的效果。

`animation-timing-function` 的 `ease` 和 `linear` 有什麼區別?

ease 是預設值,動畫以慢速開始、加速、再減速結束,呈現自然的運動感。linear 則是從頭到尾速度完全一致,呈現機械式的勻速運動。

動畫結束後,元素怎麼停留在最後的樣式?

使用 animation-fill-mode: forwards。這會讓元素在動畫結束後,持續保持最後一個關鍵影格所定義的樣式,不會回到初始狀態。這在淡入效果中非常實用。

`animation-delay` 設定負值有什麼效果?

設定負值的延遲時間,動畫會立即開始,但會從動畫序列中「已經過去」的時間點開始播放,跳過前面的部分。例如,一個 1 秒的動畫設定 animation-delay: -0.5s,會從中間位置開始播放。這常用於錯開多個相同動畫的起始時間,創造連續的波浪效果。

Animate.css 這類工具和直接寫 CSS Animation 有什麼優缺點?

動畫庫如 Animate.css 的優點是效果豐富、即套即用、無需撰寫 @keyframes,能加速開發。缺點是會引入額外的檔案大小,且效果難以深度客製化。原生 CSS Animation 完全客製、無任何依賴,性能可控,但開發時間較長,需要自行定義所有細節。

如何確保 CSS 動畫不會影響頁面性能?

優先為 transform(包含 translate, scale, rotate)和 opacity 這兩個屬性添加動畫。因為它們不會觸發佈局(Layout)與繪製(Paint)計算,瀏覽器可以將其提升至合成器線程處理,確保流暢的 60fps 動畫。應盡量避免對 width、height、top、left 等會觸發佈局重排的屬性進行動畫。