基礎知識
通過定義一段動畫中的關鍵點、關鍵狀態來創建動畫。@Keyframes相比transition對動畫過程和細節有更強的控制。
過渡動畫是兩個狀態間的變化,幀動畫可以處理動畫過程中不同時間的細節變化,
對過渡動畫理解后再學習習幀動畫會非常容易,也可以把幀動畫理解為多個幀之間的過渡動畫。
一句話,幀動畫是CSS中的大殺器,你應該充分的了解並掌握它。
關鍵幀
使用@keyframes 規則配置動畫中的各個幀
from 表示起始點
to表示終點
可以使用百分數如 20% 代表動畫運行到20%處
基本使用
下面使用 @keyframes 定義了動畫叫 radius 並配置了兩個幀動作from/to ,然后在main:hover div中使用animation-name 引用了動畫並使用animation-duration聲明執行三秒。
注意:動畫命名不要使用CSS關鍵字如
none

可以看到上面的動畫是從30%的圓角過渡到了50%的圓角,但是整個動畫的結束是瞬間結束,整個動畫並不完美。
不要着急,下面會介紹各種方法讓你的幀動畫隨心所欲。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 200px; width: 200px; display: flex; justify-content: center; align-items: center; border: 1px solid #ddd; } div{ height: 100px; width: 100px; background: #5352ed; } main:hover div{ /* 一組幀的名字 */ animation-name: radius; /* 動畫時長 */ animation-duration: 3s; } @keyframes radius{ from{ border-radius: 30%; } to{ border-radius: 50%; } } </style> </head> <body> <main> <div></div> </main> </body> </html>
時間點
幀動畫需要定義在不同時間執行的動作,開始與結束可以使用 form/to 或 0%/100% 聲明。
必須添加百分號,25%是正確寫法
時間點沒有順序要求,即100%寫在25%前也可以
未設置
0%與100%時將使用元素原始狀態
你可以這么理解,目前所學的一組幀動畫它的運行應該是這樣的
初始狀態 ---> 0% 或者 from ---> 100% 或者 to ---> 初始狀態
所以現在看上面的動畫,就知道為什么看起來比較生硬了。
物體移動
下面定義不同時間點來讓物體元素移動一圈,下例中可以不設置from/to 系統將定義為元素初始狀態。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 400px; display: flex; justify-content: flex-start; align-items: flex-start; border: 1px solid #ddd; } div{ height: 100px; width: 100px; background: #5352ed; } main:hover div{ /* 一組幀的名字 */ animation-name: move; /* 動畫時長 */ animation-duration: 3s; } @keyframes move{ /* 初始狀態 ---> 幀 ---> 初始狀態 */ 25%{ transform: translate(300px,0); } 50%{ transform: translate(300px,300px); } 75%{ transform: translate(0,300px); } } </style> </head> <body> <main> <div></div> </main> </body> </html>
同時聲明
時間點可以動畫樣式一樣時可以一起聲明,下面將25%/75%背景一起聲明。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 400px; display: flex; justify-content: flex-start; align-items: flex-start; border: 1px solid #ddd; } div{ height: 100px; width: 100px; background: #5352ed; } main:hover div{ /* 一組幀的名字 */ animation-name: move; /* 動畫時長 */ animation-duration: 3s; } @keyframes move{ /* 初始狀態 ---> 幀 ---> 初始狀態 */ 25%{ transform: translate(300px,0); } 50%{ transform: translate(300px,300px); } 75%{ transform: translate(0,300px); } 25%,75%{ background: #ff4757; } 50%,100%{ background: #5352ed; } } </style> </head> <body> <main> <div></div> </main> </body> </html>
使用動畫
使用animation-name 規則可以在元素身上同時使用多個動畫。
使用多個動畫時用逗號分隔多個
動畫有相同屬性時,后面動畫的屬性優先使用
基本使用

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 400px; display: flex; justify-content: flex-start; align-items: flex-start; border: 1px solid #ddd; } div{ height: 100px; width: 100px; background: #5352ed; } main:hover div{ /* 一組幀的名字 可以使用多組幀*/ animation-name: move,radius; /* 動畫時長 */ animation-duration: 3s; } @keyframes move{ /* 初始狀態 ---> 幀 ---> 初始狀態 */ 25%{ transform: translate(300px,0); } 50%{ transform: translate(300px,300px); } 75%{ transform: translate(0,300px); } /* 相同設置,前者不生效 */ 25%,75%{ background: #ff4757; } 50%,100%{ background: #5352ed; } } @keyframes radius{ 25%{ border-radius: 50%; } 50%{ border-radius: 30%; } 75%{ border-radius: 50%; }/* 相同設置后者覆蓋前者,所以移動時的顏色會變為下面兩種 */ 25%,75%{ background: #ffa502; } 50%,100%{ background: #2ed573; } } </style> </head> <body> <main> <div></div> </main> </body> </html>
動畫時間
使用 animation-duration 可以聲明動畫播放的時間,即把所有幀執行一遍所需要的時間。
可以使用m秒,ms毫秒時間單位
可為不同動畫單獨設置執行時間
如果動畫數量大於時間數量,將重新從時間列表中計算 。 如一個動畫有Move,Radius,Background 而時間是1s,2s,那么Move的時間是1s,Radius的時間是2s,Background的時間從頭開始數,又是1s.
效果體驗
如下圖的過渡時間,圓角是六秒完成,背景色是四秒完成,移動是兩秒完成,但是他們的開始時間都是一樣的。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 400px; display: flex; justify-content: center; align-items: flex-start; border: 1px solid #ddd; } div{ height: 100px; width: 100px; background: #5352ed; } main:hover div{ /* 一組幀的名字 可以使用多組幀*/ animation-name: radius,background,move; /* 動畫時長 圓角是六秒完成,背景色是四秒完成,移動是兩秒完成,但是他們的開始時間都是一樣的 */ animation-duration: 6s,4s,2s; /* 將動畫停留在最后一幀 */ animation-fill-mode: forwards; } @keyframes radius{ to{ border-radius: 50%; } } @keyframes background{ to{ } } @keyframes move{ to{ transform: translate(0,150px); } } </style> </head> <body> <main> <div></div> </main> </body> </html>
動畫屬性
不是所有css屬性都有過渡效果,
如何理解中間值?
比如,一個元素的寬度從100px變為200px,那么它們之間就有中間值。
而一個元素的邊框樣式從實心線變為虛心線,他們就沒有中間值。
效果體驗
看下面這張圖,從實心線變為虛心線是瞬間變化,而背景顏色的改變卻是跟着動畫時間來進行漸變的。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 400px; display: flex; justify-content: center; align-items: center; border: 1px solid #ddd; } div{ height: 200px; width: 200px; background: #5352ed; /* 添加實心線 */ border: 15px solid red; } main:hover div{ /* 一組幀的名字 可以使用多組幀*/ animation-name: border-style,background; /* 動畫時長 */ animation-duration: 2s; /* 將動畫停留在最后一幀 */ animation-fill-mode: forwards;} @keyframes border-style{ to{ border:15px dotted red ; } } @keyframes background{ to{ } } </style> </head> <body> <main> <div></div> </main> </body> </html>
中間值
可以看下下面這個例子,左邊的塊from與to設置的尺寸單位沒有中間值,所以是瞬間變大。
而右邊塊的from與to設置的尺寸單位是具有中間值的,所以是跟隨動畫時間進行漸變。

<!DOCTYPE html> <html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main { height: 400px; width: 400px; display: flex; justify-content: space-evenly; align-items: center; border: 1px solid #ddd; } main div:nth-child(1) { background: #5352ed; } main div:nth-child(2) { background: #ff4757; } main:hover div:nth-child(1) { /* 一組幀的名字 可以使用多組幀*/ animation-name: size-percentage; /* 動畫時長 */ animation-duration: 2s; /* 將動畫停留在最后一幀 */ animation-fill-mode: forwards;} main:hover div:nth-child(2) { /* 一組幀的名字 可以使用多組幀*/ animation-name: size-px; /* 動畫時長 */ animation-duration: 2s; /* 將動畫停留在最后一幀 */ animation-fill-mode: forwards;} @keyframes size-percentage { from { width: 200px; height: 200px; }/* px 與 % 之間沒有中間值,所以是瞬間出現 */ to { width: 50%; height: 50%; } } @keyframes size-px { from { width: 100px; height: 100px; }/* 有中間值,跟隨動畫時間進行漸變 */ to { width: 200px; height: 200px; } } </style> </head><body> <main> <div></div> <div></div> </main> </body></html>
重復動畫
使用animation-iteration-count 規則設置動畫重復執行次數,可以給一個數字。當設置值為 infinite 表示無限循環執行。
可同時設置元素的多個動畫重復,使用逗號分隔
如果動畫數量大於重復數量定義,后面的動畫將重新計算重復
效果體驗
如下面這個案例,移動的次數是一次,而變化圓角是無限次。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 400px; display: flex; justify-content: flex-start; align-items: flex-start; border: 1px solid #ddd; } div{ height: 100px; width: 100px; background: #5352ed; } main:hover div{ /* 一組幀的名字 可以使用多組幀*/ animation-name: move,radius; /* 動畫時長 */ animation-duration: 3s; /* 代表移動只走一遍,隨后就不斷的圓角變化,進入死循環 */ animation-iteration-count: 1,infinite; } @keyframes move{ /* 初始狀態 ---> 幀 ---> 初始狀態 */ 25%{ transform: translate(300px,0); } 50%{ transform: translate(300px,300px); } 75%{ transform: translate(0,300px); } /* 相同設置,前者不生效 */ 25%,75%{ background: #ff4757; } 50%,100%{ background: #5352ed; } } @keyframes radius{ 25%{ border-radius: 50%; } 50%{ border-radius: 30%; } 75%{ border-radius: 50%; }/* 相同設置后者覆蓋前者,所以移動時的顏色會變為下面兩種 */ 25%,75%{ background: #ffa502; } 50%,100%{ background: #2ed573; } } </style> </head> <body> <main> <div></div> </main> </body> </html>
心動感覺
使用循環動畫繪制心動效果。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css"> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 400px; display: flex; justify-content: center; align-items: center; border: 1px solid #ddd; } main i.iconfont{ font-size: 100px; color: red; } main:hover i{ /* 添加一組幀動畫 */ animation-name: xin; /* 時間 */ animation-duration: .5s; /* 循環次數 死循環 */ animation-iteration-count: infinite; } @keyframes xin { to{ opacity: .5; font-size: 120px; } 20%{ opacity: .6; font-size: 130px; } 40%{ opacity: .7; font-size: 140px; } 60%{ opacity: .8; font-size: 150px; } 80%{ opacity: .9; font-size: 160px; } to{ opacity: 1; font-size: 140px; } } </style> </head> <body> <main> <i class="iconfont icon-xin"></i> </main> </body> </html>
動畫方向
使用 animation-direction 控制動畫運行的方向。
| 選項 | 說明 |
|---|---|
| normal | 從0%到100%運行動畫 |
| reverse | 從100%到0%運行動畫 |
| alternate | 先從0%到100%,然后從100%到0% |
| alternate-reverse | 先從100%到0%,然后從0%到100% |
效果對比

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css"> <style> * { margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main { height: 400px; width: 800px; display: flex; justify-content: space-evenly; align-items: center; border: 1px solid #ddd; } main i.iconfont { font-size: 100px; color: red; position: relative; } main:hover i { /* 添加一組幀動畫 */ animation-name: xin; /* 時間 */ animation-duration: .5s; /* 循環次數 死循環 */ animation-iteration-count: infinite; } main i:nth-child(1):after { content: "normal"; font-size: 15px; color: white; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } main i:nth-child(2):after { content: "normal-reverse"; font-size: 15px; color: white; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } main i:nth-child(3):after { content: "alternate"; font-size: 15px; color: white; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } main i:nth-child(4):after { content: "alternate-reverse"; font-size: 15px; color: white; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } main:hover i:nth-child(1) { /* 0-100 */ animation-direction: normal; } main:hover i:nth-child(2) { /* 100-0 */ animation-direction: reverse; } main:hover i:nth-child(3) { /* 0-100 100-0 */ animation-direction: alternate; } main:hover i:nth-child(4) { /* 100-0 0-100 */ animation-direction: alternate-reverse; } @keyframes xin { to { opacity: .5; font-size: 120px; } 20% { opacity: .6; font-size: 130px; } 40% { opacity: .7; font-size: 140px; } 60% { opacity: .8; font-size: 150px; } 80% { opacity: .9; font-size: 160px; } to { opacity: 1; font-size: 140px; } } </style> </head> <body> <main> <i class="iconfont icon-xin"></i> <i class="iconfont icon-xin"></i> <i class="iconfont icon-xin"></i> <i class="iconfont icon-xin"></i> </main> </body> </html>
彈跳球
alternate-reverse是100-0 0-100,因此非常適合用來做彈跳球。
我們先把球和陰影都定義在下方,然后使用alternate-reverse將球轉移到上方即可。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css"> <style> * { margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main { height: 400px; width: 400px; display: flex; flex-flow: column; justify-content: flex-end; align-items: center; border: 1px solid #ddd; } main div { height: 100px; width: 100px; background: linear-gradient(45deg, #7bed9f, #2ed573, #1e90ff, #3742fa); border-radius: 50%; } main section { width: 140px; height: 20px; background: #2f3542; border-radius: 75%; /* 高斯模糊 */ filter: blur(3px); } main:hover div { /* 添加一組幀動畫 */ animation-name: beat; /* 動畫時間 */ animation-duration: 1s; /* 運動方式 100-0 0-100 */ animation-direction: alternate-reverse; /* 死循環 */ animation-iteration-count: infinite; } main:hover section { /* 添加一組幀動畫 */ animation-name: size; /* 動畫時間 */ animation-duration: 1s; /* 運動方式 100-0 0-100 */ animation-direction: alternate-reverse; /* 死循環 */ animation-iteration-count: infinite; } @keyframes beat { from{ background: linear-gradient(90deg, #7bed9f, #2ed573, #1e90ff, #3742fa); width: 140px; } to { transform: translateY(-280px); } } @keyframes size{ to{ width: 70px; } } </style> </head> <body> <main> <div></div> <section></section> </main> </body> </html>
延遲動畫
使用 animation-delay 規則定義動畫等待多長時間后執行。
我們可以為多個動畫指定不同的延遲時間,與動畫時間的使用規則相同。
效果體驗
延遲動畫 圓角3s后執行,背景色2s后執行,移動1s后執行

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 400px; display: flex; justify-content: center; align-items: flex-start; border: 1px solid #ddd; } div{ height: 100px; width: 100px; background: #5352ed; } main:hover div{ /* 一組幀的名字 可以使用多組幀*/ animation-name: radius,background,move; /* 動畫時長 */ animation-duration: 2s; /* 延遲動畫 圓角3s后執行,背景色2s后執行,移動1s后執行*/ animation-delay:3s,2s,1s; /* 將動畫停留在最后一幀 */ animation-fill-mode: forwards; } @keyframes radius{ to{ border-radius: 50%; } } @keyframes background{ to{ background-color: #ffa502; } } @keyframes move{ to{ transform: translate(0,150px); } } </style> </head> <body> <main> <div></div> </main> </body> </html>
動畫速率
系統屬性
使用animation-timing-function來控制動畫速率
| 值 | 描述 |
|---|---|
| linear | 規定以相同速度開始至結束的過渡效果(等於 cubic-bezier(0,0,1,1))。 |
| ease | 開始慢,然后快,慢下來,結束時非常慢(cubic-bezier(0.25,0.1,0.25,1))默認值。 |
| ease-in | 開始慢,結束快(等於 cubic-bezier(0.42,0,1,1)) |
| ease-out | 開始快,結束慢(等於 cubic-bezier(0,0,0.58,1)) |
| ease-in-out | 中間快,兩邊慢(等於 cubic-bezier(0.42,0,0.58,1)) |
| cubic-bezier(n,n,n,n) | 在 cubic-bezier 函數中定義自己的值 |
可以在幀中單獨定義,將影響當前幀的速率
貝塞爾曲線
其實不管是linear或者是ease都是由貝塞爾曲線來完成的。
我們需要設置四個值 cubic-bezier(<x1>, <y1>, <x2>, <y2>)來控制曲線速度,可在

效果體驗

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 400px; display: flex; justify-content: space-evenly; align-items: flex-end; border: 1px solid #ddd; } div{ padding: 10px; height: 100%; width: 25%; text-align: center; background: #ff4757 content-box; color: white; } main:hover div{ /* 一組幀的名字 可以使用多組幀*/ animation-name: move; /* 動畫時長 */ animation-duration: 3s; /* 重復動畫 死循環 */ animation-iteration-count: infinite; } main:hover div:nth-child(1){ animation-timing-function: linear; } main:hover div:nth-child(2){ animation-timing-function: ease; } main:hover div:nth-child(3){ animation-timing-function: ease-in; } main:hover div:nth-child(4){ animation-timing-function: ease-out; } main:hover div:nth-child(5){ animation-timing-function: ease-in-out; } @keyframes move{ to{ height: 0; } } </style> </head> <body> <main> <div>linear</div> <div>ease</div> <div>ease-in</div> <div>ease-out</div> <div>ease-in-out</div> </main> </body> </html>
彈跳球
ease-out是開始快,結束慢,而ease-in是結束快,開始慢。因此這兩個組合做彈跳小球剛好。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css"> <style> * { margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main { height: 400px; width: 400px; display: flex; flex-flow: column; justify-content: space-between; align-items: center; border: 1px solid #ddd; } main div { height: 100px; width: 100px; background: linear-gradient(45deg, #eccc68, #ffa502, #ff6b81, #ff4757); border-radius: 50%; } main section { width: 70px; height: 20px; background: #2f3542; border-radius: 75%; /* 高斯模糊 */ filter: blur(3px); } main:hover div { /* 添加一組幀動畫 */ animation-name: beat; /* 動畫時間 */ animation-duration: 3s; /* 死循環 */ animation-iteration-count: infinite; } main:hover section { /* 添加一組幀動畫 */ animation-name: size; /* 動畫時間 */ animation-duration: 3s; /* 死循環 */ animation-iteration-count: infinite; } @keyframes beat { 0% { background: linear-gradient(60deg, #eccc68, #ffa502, #ff6b81, #ff4757); transform: translateY(0px); animation-timing-function: ease-in; width: 100px; } 30% { background: linear-gradient(120deg, #eccc68, #ffa502, #ff6b81, #ff4757); transform: translateY(50px); animation-timing-function: ease-in; width: 100px; } 60% { background: linear-gradient(240deg, #eccc68, #ffa502, #ff6b81, #ff4757); transform: translateY(100px); animation-timing-function: ease-in; width: 100px; } 80% { background: linear-gradient(300deg, #eccc68, #ffa502, #ff6b81, #ff4757); transform: translateY(150px); animation-timing-function: ease-in; width: 100px; } 95% { background: linear-gradient(340deg, #eccc68, #ffa502, #ff6b81, #ff4757); transform: translateY(200px); animation-timing-function: ease-in; width: 100px; } 15%, 45%, 70%, 85%, 100% { width: 140px; transform: translateY(280px); animation-timing-function: ease-out; } } @keyframes size { 0% { width: 80px; } 30% { width: 85px; } 60% { width: 95px; } 80% { width: 110px; } 95% { width: 120px; } 15%, 45%, 70%, 85%, 100% { width: 140px; } } </style> </head> <body> <main> <div></div> <section></section> </main> </body> </html>
按鈕提交
這個需要用到盒子陰影,一個元素可以有多個陰影。
盒子陰影的設置規則如下:
水平偏移度/垂直偏移度/模糊度/顏色
對於顏色而言可以使用currentColor來獲取當前盒子的color屬性。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="//at.alicdn.com/t/font_1953712_q6h4xm8p2jc.css" type="text/css"> <style> * { margin: 0; padding: 0; list-style: none; box-sizing: border-box; } body { height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main { height: 400px; width: 400px; display: flex; justify-content: center; align-items: center; border: 1px solid #ddd; } main button { height: 40px; width: 100px; background-color: #747d8c; color: white; display: flex; justify-content: center; align-items: center; } main button::after { content: ''; display: inline-block; height: 3px; width: 3px; margin-left: 5px; } /* Js中可換成點擊事件 */ button:hover::after { /* 添加一組幀動畫 */ animation-name: point; /* 動畫時間 */ animation-duration: 2s; /* 死循環 */ animation-iteration-count: infinite; /* 動畫速率 */ animation-timing-function: linear; } @keyframes point { 60%{ box-shadow: none; } 30% { box-shadow: 3px 0 currentColor; } 60% { box-shadow: 3px 0 currentColor, 9px 0 currentColor; } to { box-shadow: 3px 0 currentColor, 9px 0 currentColor, 15px 0 currentColor; } } </style> </head> <body> <main> <button>提交</button> </main> </body> </html>
步進速度
過渡使用階梯化呈現,有點像現實生活中的機械舞,下面是把過渡分3步完成。
| 選項 | 說明 |
|---|---|
| steps(n,start) | 設置n個時間點,第一時間點變化狀態 |
| steps(n,end) | 設置n個時間點,第一時間點初始狀態 |
| step-start | 等於steps(1,start),可以理解為從下一步開始 |
| step-end | 等於steps(1,end),可以理解為從當前步開始 |
start總是先走,end總是后走.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; box-sizing: border-box; } body{ height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; } main{ height: 400px; width: 800px; display: flex; border:1px solid #ddd; position: relative; } main div{ width: 200px; height: 100%; border: 1px solid #ddd; } main::after{ content: "START"; height: 30%; width: 25%; background: #ff4757; color: #fff; font-size: 2em; position: absolute; top: 0; display: flex; justify-content: center; align-items: center; } main::before{ content: "END"; height: 30%; width: 25%; background: #70a1ff; color: #fff; font-size: 2em; position: absolute; bottom: 0; display: flex; justify-content: center; align-items: center; } main:hover::after{ /* 添加一組動畫幀 */ animation-name: move; /* 步進動畫,3步 */ animation-timing-function: steps(3,start); /* 動畫時長2s */ animation-duration: 2s; } main:hover::before{ /* 添加一組動畫幀 */ animation-name: move; /* 步進動畫,3步 */ animation-timing-function: steps(3,end); /* 動畫時長2s */ animation-duration: 2s; } @keyframes move{ to{ transform: translateX(600px); } } </style> </head> <body> <main> <div></div> <div></div> <div></div> <div></div> </main> </body> </html>
播放狀態
使用 animation-play-state 可以控制動畫的暫停與運行。
| 選項 | 說明 |
|---|---|
| paused | 鼠標放上時暫停 |
| running | 鼠標放上時運行 |
輪播圖

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { padding: 0; margin: 0; } body { width: 100vw; height: 100vh; display: flex; justify-content: center; align-items: center; background: #2c3e50; } main { width: 400px; border: solid 5px #ddd; border-width: 5px 0 5px 0; overflow: hidden; position: relative; } main:hover section { animation-play-state: paused; } main:hover ul::before { animation-play-state: paused; } section { width: 1600px; height: 200px; display: flex; flex-direction: row; animation-name: slide; animation-duration: 4s; animation-iteration-count: infinite; animation-timing-function: steps(4, end); } section div { width: 400px; height: 200px; overflow: hidden; } section div img { width: 100%; } ul { width: 200px; position: absolute; list-style: none; display: flex; justify-content: center; align-items: center; z-index: 3; bottom: 20px; left: 50%; transform: translateX(-50%); } ul li { font-size: 2em; font-weight: bold; color: white; width: 50px; height: 50px; border-radius: 50%; border: solid 3px transparent; box-sizing: border-box; display: flex; justify-content: center; align-items: center; z-index: 2; background: rgba(0, 0, 0, .3); box-shadow: 0 0 3px rgba(0, 0, 0, 1); } ul::before { content: ''; width: 50px; height: 50px; border-radius: 50%; position: absolute; background: #e74c3c; left: 0; animation-name: num; animation-duration: 4s; animation-iteration-count: infinite; animation-timing-function: steps(4, end); z-index: 1; } @keyframes slide { from { transform: translateX(0px); } to { transform: translateX(-100%); } } @keyframes num { 100% { transform: translateX(200px); } } </style> </head> <body> <main> <section> <div> <img src="1.jpg" alt=""> </div> <div> <img src="2.jpg" alt=""> </div> <div> <img src="3.jpg" alt=""> </div> <div> <img src="4.jpg" alt=""> </div> </section> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </main> </body> </html>
填充模式
animation-fill-mode 用於定義動畫播放結束后的處理模式,是回到原來狀態還是停止在動畫結束狀態。
| 選項 | 說明 |
|---|---|
| none | 需要等延遲結束,起始幀屬性才應用 |
| backwards | 動畫效果在起始幀,不等延遲結束 |
| forwards | 結束后停留動畫的最后一幀 |
| both | 包含backwards與forwards規則,即動畫效果在起始幀,不等延遲結束,並且在結束后停止在最后一幀 |
效果對比

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; box-sizing: content-box; } body{ display: flex; justify-content: center; align-items: center; height: 100vh; width: 100vw; } main{ display: flex; justify-content: space-evenly; align-items: center; height: 200px; width: 800px; border: 1px solid #ddd; } div{ height: 80px; width: 200px; background: #000 content-box; padding: 10px; display: flex; justify-content: space-evenly; align-items: center; color: #fff; position: relative; } main:hover div{ /* 添加一組幀動畫 */ animation-name: background; /* 運行時間 */ animation-duration: 3s; /* 延遲時間 */ animation-delay: 2s; } main div:nth-child(1)::before{ content: "等待延遲 不停留最后一幀"; display: flex; justify-content: space-evenly; align-items: center; color: red; font-weight: bolder; position: absolute; top: -20px; } main div:nth-child(2)::before{ content: "不等待延遲 不停留最后一幀 "; display: flex; justify-content: space-evenly; align-items: center; color: red; font-weight: bolder; position: absolute; top: -20px; } main div:nth-child(3)::before{ content: "等待延遲 停留最后一幀 "; display: flex; justify-content: space-evenly; align-items: center; color: red; font-weight: bolder; position: absolute; top: -20px; } main div:nth-child(4)::before{ content: "不等待延遲 停留最后一幀 "; display: flex; justify-content: space-evenly; align-items: center; color: red; font-weight: bolder; position: absolute; top: -20px; } main:hover div:nth-child(1){ animation-fill-mode: none; } main:hover div:nth-child(2){ animation-fill-mode: backwards; } main:hover div:nth-child(3){ animation-fill-mode: forwards; } main:hover div:nth-child(4){ animation-fill-mode: both; } @keyframes background{ from{ background-color: #ff6348; } 30%{ background-color: #ffa502; } 60%{ background-color: #eccc68; } to{ background-color: #2ed573; } } </style> </head> <body> <main> <div>none</div> <div>backwards</div> <div>forwards</div> <div>both</div> </main> </body> </html>
簡寫模式
和CSS中的其他屬性一樣,可以使用animation組合定義幀動畫。animation 屬性是一個簡寫屬性,用於設置六個動畫屬性:
-
-
animation-name 幀動畫名字
-
animation-duration 幀動畫運行時間
-
animation-timing-function 幀動畫速率
-
animation-delay 幀動畫播放狀態(暫停/運行)
-
animation-iteration-count 幀動畫循環次數
-
animation-direction 延遲時間
-
必須存在 animation-duration
