動畫 animation
隨著瀏覽器對於 CSS 的支援度提升,現在已經可以透過 CSS 做出許多酷炫的「動畫」效果,這篇教學會先從 CSS 的 @keyframes 定義動畫影格,逐一介紹 CSS animation 各個樣式屬性,例如 animation-name、animation-duration、animation-delay、animation-timing-function、animation-direction...等,透過這些動畫樣式屬性實作 CSS 動畫。
快速導覽:
@keyframe 定義動畫影格
要使用 CSS 製作動畫,必須先透過 @keyframe
定義動畫的影格,@keyframe
的基本寫法需要包含「name、from、to」三個關鍵字,基本寫法如下:
@keyframe 關鍵字 |
說明 |
---|---|
name | 這組影格的名稱。 |
from | 起始樣式的屬性值。 |
to | 結束樣式的屬性值。 |
@keyframes name {
from {
樣式: 屬性值;
}
to {
樣式: 屬性值;
}
}
定義名稱關鍵字 name 時,可使用英文字母大小寫、數字、連接線「-」或底線「_」,並有下列幾點需要注意:
- 名稱開頭需為英文字母 ( 可用單一底線開頭 )。
- 名稱大小寫有區別。
- 名稱可以加引號、亦可不加引號。
- 如果有兩組
@keyframes
,同名,以後面的名稱為主。- 不能使用
None
或initial
作為名稱 ( 這兩個是 CSS 保留字 ),如果真的要使用,需要使用引號包覆,例如"None"
或"initial"
。
@keyframes oxxo { ... }
@keyframes "oxxo" { ... } /* 位於下方,若和上方同名,則會採用這個 */
@keyframes OXXO { ... } /* 大小寫與 oxxo 不同,屬於完全不同的影格定義 */
@keyframes initial { ... } /* 不可使用 */
@keyframes None { ... } /* 不可使用 */
@keyframes "initial" { ... } /* 可以用 */
@keyframes "None" { ... } /* 可以用 */
下方範例使用 @keyframe
定義了一組名為為 oxxo 的影格,並指定起始的 width
和 height
樣式屬性值為 50px,結束的 width
和 height
樣式屬性值為 200px,藉著透過 animation-name
執行這組影格,animation-duration
定義這組影格漸變的時間,網頁執行後,當滑鼠移動到紅色方塊上方,紅色方塊就會變大,動畫結束後會回覆原本的樣式設定。
<!-- HTML 程式碼-->
<div></div>
<!-- CSS 程式碼 -->
<style>
div{
width:50px;
height:50px;
background:#f00;
}
div:hover {
animation-name: oxxo; /* 使用 oxxo 影格定義執行動畫 */
animation-duration: 2s; /* 動畫時間為 2 秒 */
}
@keyframes oxxo{
from{
width: 50px;
height: 50px;
}
to{
width: 200px;
height: 200px;
}
}
</style>
除了使用 @keyframe
關鍵字 from
和 to
,也可以使用「百分比」的方式增加動畫過程中的關鍵影格,百分比數值和關鍵字可以混合使用,關鍵字 from
等同「0%」,to
等同「100%」,下方範例會使用百分比的方式,在動畫過程中加入 33% 與 66% 兩組關鍵影格,網頁執行後會看見紅色方塊先改變 width
,再改變 height
,最後又會回到原本的大小。
注意,關鍵影格的 0% 必須要有「%」單位。
<!-- HTML 程式碼-->
<div></div>
<!-- CSS 程式碼 -->
<style>
div{
width:50px;
height:50px;
background:#f00;
}
div:hover {
animation-name: oxxo;
animation-duration: 4s;
}
@keyframes oxxo{
from, to{
width: 50px;
height: 50px; /* 因為 from 和 to 內容相同,可使用 CSS 的寫法寫在一起 */
}
33% {
width: 200px;
height: 50px; /* 如果沒有寫這一段,則會出現 0% 到 66% 的高度變化 */
}
66% {
width: 200px;
height: 200px;
}
}
</style>
如果省略了 from、0% 或 to、100%,就會使用元素「原本的樣式」替代,下方的範例省略了 from 和 to,產生的結過就與上方範例完全相同。
<!-- HTML 程式碼-->
<div></div>
<!-- CSS 程式碼 -->
<style>
div{
width:50px;
height:50px;
background:#f00;
}
div:hover {
animation-name: oxxo;
animation-duration: 4s;
}
@keyframes oxxo{
33% {
width: 200px;
height: 50px; /* 如果沒有寫這一段,則會出現 0% 到 66% 的高度變化 */
}
66% {
width: 200px;
height: 200px;
}
}
</style>
注意,能夠在動畫效果中加入補間動畫數值的樣式屬性,需要具備能「計算」的屬性值,例如顏色、位置、尺寸、角度、透明度...等,如果是使用「關鍵字」作為屬性值的樣式,則無法加入補間動畫效果,例如 none
、solid
、dashed
...等,此外,若支援動畫的樣式*使用 auto
、max-content
等關鍵字作為屬性值 ( 或不設定任何屬性值 ),也會無法順利產生補間動畫 ( 或產生不如預期的效果 )*。
下方範例使用 max-content
和 auto
作為屬性值,會產生不如預期的效果 ( 結束時區塊消失 )。
<!-- HTML 程式碼-->
<div></div>
<!-- CSS 程式碼 -->
<style>
div{
width: max-content; /* 使用 max-content */
height: auto; /* 使用 auto */
background:#f00;
}
div:hover {
animation-name: oxxo;
animation-duration: 4s;
}
@keyframes oxxo{
33% {
width: 200px;
height: 50px;
}
66% {
width: 200px;
height: 200px;
}
}
</style>
animation-name 動畫名稱
animation-name
表示「動畫名稱」的樣式屬性,沒有繼承特性,這個樣式屬性會執行「特定名稱的影格定義」,是操作 CSS 動畫時的「必要」樣式屬性,需要注意使用時名稱「不能加上引號」。
div {
animation-name: oxxo;
}
@keyframes oxxo{
50% {background: green;}
}
animation-duration 動畫持續時間
animation-duration
表示「動畫持續時間」的樣式屬性,換句話說就是「from 到 to」要經過的時間,沒有繼承特性,使用非負值的數值,數值需要搭配「s」( 秒 ) 或「ms」( 1/1000 秒、毫秒 ) 等時間單位,是操作 CSS 動畫時的「必要」樣式屬性。
div {
animation-name: oxxo;
animation-duration: 1s; /* 動畫總時長 1 秒 */
}
@keyframes oxxo{
50% {background: green;}
}
animation-iteration-count 動畫播放次數
animation-iteration-count
表示「動畫播放的次數」,預設值為 1 次,沒有繼承特性,如果設定為 infinite
動畫就會無止盡的播放下去。
div {
animation-name: oxxo;
animation-duration: 1s;
animation-iteration-count: 2; /* 播放兩次 */
}
@keyframes oxxo{
50% {background: green;}
}
animation-delay 動畫延遲時間
animation-delay
表示「動畫延遲時間」,沒有繼承特性,需要搭配「s」( 秒 ) 或「ms」( 1/1000 秒、毫秒 ) 等時間單位,如果沒有設定或將其設為 0s,動畫就會直接播放不會延遲。如果將延遲播放時間設定為「負值」 ( 例如 -1s、-2s ),就會產生「快轉」的效果,假設一段動畫持續時間為 5 秒,animation-delay
設定為 -2s,動畫將會直接從第二秒的位置開始播放,播放三秒後停止 ( 5-2=3 )。
下方範例有三個不同顏色的方塊,都套用同樣的 oxxo 影格定義,動畫也都設定為持續 5 秒,但是藍色的 animation-delay
設為 2s,紅色的 animation-delay
設為 -2s,綠色則完全不設定 animation-delay
,執行後藍色會慢兩秒移動,紅色會直接跳到已經移動兩秒的地方再開始移動,綠色則是一開始就移動。
<!-- HTML 程式碼-->
<h2>滑鼠移動到我上方開始動畫</h2>
<div class="r"></div>
<div class="g"></div>
<div class="b"></div>
<!-- CSS 程式碼 -->
<style>
div {
width: 50px;
height: 50px;
margin: 10px;
}
h2:hover~div{
animation-name: oxxo;
animation-duration: 5s;
}
.r{
background: #f00;
animation-delay: -2s; /* 快轉 */
}
.g{background: #0a0;}
.b{
background: #00c;
animation-delay: 2s; /* 延遲 */
}
@keyframes oxxo {
from {margin-left: 10px;}
to {margin-left: 200px;}
}
</style>
animation-timing-function 動畫速度
animation-timing-function
表示「動畫的速度」,預設值為 ease
,沒有繼承特性,這個樣式屬性可以讓動畫播放的「每個關鍵影格之間」具有「加速、減速、平緩加速、線性移動」等速度變化,根據「W3C CSS Easing Functions Level 1」的說明,共有下列幾種屬性值:
屬性值 | 說明 |
---|---|
linear | 線性,沒有加減速。 |
ease-in | 加速開始,線性停止。 |
ease-out | 線停開始,減速停止。 |
ease-in-out | 加速開始,減速停止。 |
ease | 加速開始,減速停止。 |
step-start | 維持在 0% 樣式,等待動畫時間過後,直接跳到 100% 樣式。 |
step-end | 直接跳到 100% 樣式,並等待動畫時間過完。 |
steps(n, jump-start) | 分成 n 個步驟跳往 100% 樣式。 |
steps(n, jump-end) | 分成 n 個步驟跳往 100% 樣式。 |
steps(n, jump-none) | 分成 n-1 個步驟跳往 100% 樣式。 |
steps(n, jump-both) | 分成 n+1 個步驟跳往 100% 樣式。 |
下方範例會讓不同的 div
從左移動到右再從右移動到左,從中可以觀察不同動畫速度的效果。
<!-- HTML 程式碼-->
<h2>滑鼠移動到我上方看效果</h2>
<h3>linear</h3><div></div>
<h3>ease-in</h3><div></div>
<h3>ease-out</h3><div></div>
<h3>ease-in-out</h3><div></div>
<h3>ease</h3><div></div>
<h3>step-start</h3><div></div>
<h3>step-end</h3><div></div>
<h3>steps(5, jump-start)</h3><div></div>
<h3>steps(5, jump-end)</h3><div></div>
<h3>steps(5, jump-none)</h3><div></div>
<h3>steps(5, jump-both)</h3><div></div>
<!-- CSS 程式碼 -->
<style>
h2 {border: 2px solid #000;}
h2:hover~div {
animation-name: oxxo;
animation-duration: 5s;
}
h3 {
margin:5px;
width: 190px;
height: 30px;
float:left;
clear: both;
text-align: right;
}
div {
float:left;
width: 30px;
height: 30px;
margin:5px;
background: red;
}
div:nth-of-type(1) {animation-timing-function: linear;}
div:nth-of-type(2) {animation-timing-function: ease-in;}
div:nth-of-type(3) {animation-timing-function: ease-out;}
div:nth-of-type(4) {animation-timing-function: ease-in-out;}
div:nth-of-type(5) {animation-timing-function: ease;}
div:nth-of-type(6) {animation-timing-function: step-start;}
div:nth-of-type(7) {animation-timing-function: step-end;}
div:nth-of-type(8) {animation-timing-function: steps(5, jump-start);}
div:nth-of-type(9) {animation-timing-function: steps(5, jump-end);}
div:nth-of-type(10) {animation-timing-function: steps(5, jump-none);}
div:nth-of-type(11) {animation-timing-function: steps(5, jump-both);}
@keyframes oxxo{
50% {margin-left: 200px;}
}
</style>
除了使用預設的動畫速度,也可以使用 CSS 內建函式 cubic-bezier
設定「客製化的動畫速度」,cubic-bezier
是一個可調整的「貝茲曲線」,總共有四個參數,分別是第一個貝茲曲線控制點 p1 的座標 (x1, y1) 和第二個貝茲曲線控制點 p2 的座標 (x2, y2) ( 參考 Cubic Bézier )。
透過線上工具「cubic-bezier.com」可以使用視覺化的方式,拖拉這兩個控制點,調整控制點之後,上方就會看見這個動畫速度的寫法。
下方範例會透過 cubic-bezier
,產生四種有趣的動畫速度,從中可以看到當設定值超過範圍時,甚至會產生超過原本邊界的特殊效果。
<!-- HTML 程式碼-->
<h2>滑鼠移動到我上方看效果</h2>
<h3>cubic-bezier(.24,1.19,.68,-0.07)</h3><div></div>
<h3>cubic-bezier(.96,.34,0,.73)</h3><div></div>
<h3>cubic-bezier(.46,-0.75,.18,1.49)</h3><div></div>
<h3>cubic-bezier(.41,.86,.55,2.08)</h3><div></div>
<!-- CSS 程式碼 -->
<style>
h2 {border: 2px solid #000;}
h2:hover~div {
animation-name: oxxo;
animation-duration: 5s;
}
h3 {
margin:5px;
width: 290px;
height: 30px;
float:left;
clear: both;
text-align: right;
}
div {
float:left;
width: 30px;
height: 30px;
margin:5px;
background: red;
}
div:nth-of-type(1) {animation-timing-function: cubic-bezier(.24,1.19,.68,-0.07);}
div:nth-of-type(2) {animation-timing-function: cubic-bezier(.96,.34,0,.73);}
div:nth-of-type(3) {animation-timing-function: cubic-bezier(.46,-0.75,.18,1.49);}
div:nth-of-type(4) {animation-timing-function: cubic-bezier(.41,.86,.55,2.08);}
@keyframes oxxo{
50% {margin-left: 200px;}
}
</style>
如果熟練 steps 的用法,就能夠很簡單的使用「sprite 圖片」來做動畫,sprite 圖片就是將許多圖案集合成一張圖,接著透過 CSS 的語法使這些圖案分別呈現在網頁裡,大幅減少多張圖片載入的 request 數量,下方範例會使用一張經典的 sprite 圖片 ( Leland Stanford 所拍攝 ),透過 CSS 動畫的 steps 就能讓圖片中的馬兒跑起來。
圖片下載:Leland Stanford 馬兒圖
<!-- HTML 程式碼-->
<div></div>
<!-- CSS 程式碼 -->
<style>
div {
width: 186px;
height: 141px;
background-image: url("https://steam.oxxostudio.tw/download/css/animation-horse.jpg");
animation-name: oxxo;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-timing-function: step-start; /* 使用 step-start */
}
@keyframes oxxo{
0% {background-position: -15px -13px;}
6.25% {background-position: -210px -13px;}
12.5% {background-position: -403px -13px;}
18.75% {background-position: -592px -13px;}
25% {background-position: -15px -165px;}
31.25% {background-position: -210px -165px;}
37.5% {background-position: -403px -165px;}
43.75% {background-position: -592px -165px;}
50% {background-position: -15px -320px;}
56.25% {background-position: -210px -320px;}
62.5% {background-position: -403px -320px;}
68.75% {background-position: -592px -320px;}
75% {background-position: -15px -470px;}
81.25% {background-position: -210px -470px;}
87.5% {background-position: -403px -470px;}
93.75% {background-position: -592px -470px;}
100 %{background-position: -592px -470px;}
}
</style>
animation-direction 動畫播放方向
animation-direction
表示「動畫播放方向」的樣式屬性,沒有繼承特性,有下列幾種屬性值:
屬性值 | 說明 |
---|---|
normal | 正常播放,從 0% 到 100% ( 預設值 )。 |
reverse | 反轉播放,從 100% 到 0%。 |
alternate | 正反轉輪流播放,奇數次為 0% 到 100%,偶數次為 100% 到 0%,若動畫播放次數只有一次就只會正常播放。 |
alternate-reverse | 正反轉輪流播放,奇數次為 100% 到 0%,偶數次為 0% 到 100%,若動畫播放次數只有一次就只會反轉播放。 |
下方範例會展示這四種播放方向的效果。
<!-- HTML 程式碼-->
<h2>滑鼠移動到我上方看效果</h2>
<h3>normal</h3><div></div>
<h3>reverse</h3><div></div>
<h3>alternate</h3><div></div>
<h3>alternate-reverse</h3><div></div>
<!-- CSS 程式碼 -->
<style>
h2 {border: 2px solid #000;}
h2:hover~div {
animation-name: oxxo;
animation-duration: 2s;
animation-iteration-count: 4;
}
h3 {
margin:5px;
width: 190px;
height: 30px;
float:left;
clear: both;
text-align: right;
}
div {
float:left;
width: 30px;
height: 30px;
margin:5px;
background: red;
}
div:nth-of-type(1) {animation-direction:normal;}
div:nth-of-type(2) {animation-direction:reverse;}
div:nth-of-type(3) {animation-direction:alternate;}
div:nth-of-type(4) {animation-direction:alternate-reverse;}
@keyframes oxxo{
0% {margin-left: 5px;}
100% {margin-left: 200px;}
}
</style>
animation-fill-mode 動畫播放前後模式
animation-fill-mode
表示「動畫播放前後模式」的樣式屬性,也就是動畫完成後要停留在哪個樣式,沒有繼承特性,有下列幾種屬性值:
屬性值 | 說明 |
---|---|
none | 不論動畫播放次數,結束後返回原本樣式 ( 預設值 )。 |
forwards | 動畫結束後,保持在 100% 狀態。 |
backwards | 動畫結束後,保持在 0% 狀態 ( 大部分瀏覽器等同 none 的效果 )。 |
both | 依據動畫的次數或播放方向,保持在第一個影格或最後一個影格狀態 ( 很實用 )。 |
下方範例會展示這四種動畫播放前後模式的差異,可觀察結束後的位置和顏色。
<!-- HTML 程式碼-->
<h2>滑鼠移動到我上方看效果</h2>
<h3>none</h3><div></div>
<h3>forwards</h3><div></div>
<h3>backwards</h3><div></div>
<h3>both</h3><div></div>
<!-- CSS 程式碼 -->
<style>
h2 {border: 2px solid #000;}
h2:hover~div {
animation-name: oxxo;
animation-duration: 2s;
animation-iteration-count: 3;
animation-direction: alternate;
}
h3 {
margin:5px;
width: 100px;
height: 30px;
float:left;
clear: both;
text-align: right;
}
div {
float:left;
width: 30px;
height: 30px;
margin:5px;
background: green;
}
div:nth-of-type(1) {animation-fill-mode: none;}
div:nth-of-type(2) {animation-fill-mode: forwards;}
div:nth-of-type(3) {animation-fill-mode: backwards;}
div:nth-of-type(4) {animation-fill-mode: both;}
@keyframes oxxo{
0% {
background: red;
margin-left: 5px;
}
100% {
background: cyan;
margin-left: 200px;
}
}
</style>
animation-play-state 動畫播放或暫停
animation-play-state
表示「動畫播放或暫停」的樣式屬性,可以透過這個樣式屬性控制動畫播放或暫停,沒有繼承特性,有下列兩種屬性值:
屬性值 | 說明 |
---|---|
running | 動畫運行 ( 預設值 ) 。 |
paused | 動畫暫停。 |
下方範例執行後,當滑鼠移動到上方的按鈕,下方的動畫就會暫停,滑鼠移開之後動畫就會繼續。
<!-- HTML 程式碼-->
<h2>滑鼠移動到我上方看效果</h2>
<div></div>
<!-- CSS 程式碼 -->
<style>
h2 {
width: 300px;
border: 2px solid #000;
}
h2:hover~div {
animation-play-state: paused; /* 滑鼠移動上去時,暫停動畫 */
}
div {
width: 50px;
height: 50px;
margin:5px;
animation-name: oxxo;
animation-duration: 2s;
animation-iteration-count: infinite; /* 動畫無限播放 */
background: red;
}
@keyframes oxxo{
50% {
background: cyan;
margin-left: 200px;
}
}
</style>
animation 動畫縮寫樣式
元素套用動畫效果時,為了避免 CSS 程式碼過於冗長,有時會使用縮寫的 animation
樣式屬性,使用時只需要將動畫的個別樣式寫在後方,除了動畫持續時間和延遲時間有順序 ( 持續時間, 延遲時間 ),其他關鍵字排列沒有順序之分,但仍需注意「動畫名稱」不要與特殊關鍵字相同,下方所列出的寫法都是合乎規規則的寫法:
div {
animation: 1s oxxo; /* 持續時間 1s */
animation: oxxo 1s; /* 持續時間 1s */
animation: 1s 0.5s oxxo; /* 持續時間 1s,延遲時間 0.5s */
animation: 1s ease-in infinite oxxo; /* 持續時間 1s,使用 ease-in,無限重複 */
animation: 1s oxxo 0.5s ease-in infinite; /* 持續時間 1s,延遲時間 0.,5s,使用 ease-in,無限重複 */
animation: 1s ease-in 3 backwards oxxo; /* 持續時間 1s,使用 ease-in,重複三次,backwards 模式 */
}
下方的範例使用 animation
讓四個 div
呈現不同的動畫效果。
<!-- HTML 程式碼-->
<h2>滑鼠移動到我上方看效果</h2>
<h3>animation: 2s oxxo</h3><div></div>
<h3>animation: 2s 0.5s ease-in oxxo</h3><div></div>
<h3>animation: 4 1s oxxo ease-in</h3><div></div>
<h3>animation: 1s 1s oxxo 3 both ease-out</h3><div></div>
<!-- CSS 程式碼 -->
<style>
h2 {border: 2px solid #000;}
h3 {
margin:5px;
height: 30px;
}
div {
width: 30px;
height: 30px;
margin:5px;
background: red;
}
h2:hover~div:nth-of-type(1) {animation: 2s oxxo;}
h2:hover~div:nth-of-type(2) {animation: 2s 0.5s ease-in oxxo;}
h2:hover~div:nth-of-type(3) {animation: 4 1s oxxo ease-in;}
h2:hover~div:nth-of-type(4) {animation: 1s 1s oxxo 3 both ease-out;}
@keyframes oxxo{
50% {
background: cyan;
margin-left: 200px;
}
}
</style>
小結
animation
是一個非常好用的 CSS 樣式屬性,隨著瀏覽器的進步,目前幾乎所有的瀏覽器都支援 CSS 動畫功能,只要熟悉相關的語法,相信一定可以做出非常酷炫的動畫效果。
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~