背景知識(shí):css 動(dòng)畫規(guī)范
@keyframes
animation-name
animation-duration
animation-timing-function
animation-delay
animation-iteration-count
animation-direction
animation-play-state
animation-fill-mode
各屬性的定義及用法:
@keyframes: 用來指定CSS動(dòng)畫一次循環(huán)中,可以用百分比表示多個(gè)時(shí)間節(jié)點(diǎn)處的CSS屬性變化,關(guān)鍵字 from 等于 0%,to 等于 100%。
animation-name:指定@keyframes的名字,CSS加載時(shí)會(huì)應(yīng)用該名字的@keyframes規(guī)則來實(shí)現(xiàn)動(dòng)畫。
animation-duration:動(dòng)畫持續(xù)時(shí)間,默認(rèn)是0表示無動(dòng)畫,單位可以設(shè)s秒或ms毫秒。
animation-timing-function:動(dòng)畫播放方式,默認(rèn)值ease,可以設(shè)linear,ease,ease-in,ease-out,ease-in-out,cubic-bezier(n,n,n,n),steps。
animation-delay:延遲開始動(dòng)畫的時(shí)間,默認(rèn)值是0,表示不延遲,立即播放動(dòng)畫。單位是s秒或ms毫秒。允許設(shè)負(fù)時(shí)間,意思是讓動(dòng)畫動(dòng)作從該時(shí)間點(diǎn)開始啟動(dòng),之前的動(dòng)畫不顯示。例如 -3s 使動(dòng)畫馬上開始,但前 3 秒的動(dòng)畫被跳過。
animation-iteration-count:動(dòng)畫循環(huán)播放的次數(shù),默認(rèn)值為1,即放完一遍后不循環(huán)播放。除數(shù)字外也可以設(shè)關(guān)鍵字 infinite 表示無限循環(huán)播放。
animation-direction:動(dòng)畫播放的方向,可設(shè)normal,alternate,alternate-reverse。默認(rèn)值是 normal 表示正常播放動(dòng)畫。alternate 表示輪轉(zhuǎn)正反向播放動(dòng)畫,即動(dòng)畫會(huì)在奇數(shù)次(1,3,5…)正常播放,而在偶數(shù)次(2,4,6…)反向播放。alternate-reverse 正好反過來,奇數(shù)次反向播動(dòng)畫,偶數(shù)次正向播動(dòng)畫。
animation-play-state:動(dòng)畫的狀態(tài),可設(shè)running,paused。默認(rèn)值 running 表示正在播放動(dòng)畫,paused 表示暫停動(dòng)畫。
animation-fill-mode:動(dòng)畫的時(shí)間外屬性,可設(shè) none,forwards,backwards,both。默認(rèn)值 none 表示動(dòng)畫播完后,恢復(fù)到初始狀態(tài)。forwards 當(dāng)動(dòng)畫播完后,保持 @keyframes 里最后一幀的屬性。backwards 表示開始播動(dòng)畫時(shí),應(yīng)用 @keyframes 里第一幀的屬性,要看出效果,通常要設(shè) animation-delay 延遲時(shí)間。both 表示 forwards 和 backforwards 都應(yīng)用。
接下來看看幾個(gè)比較實(shí)用的動(dòng)畫實(shí)現(xiàn)吧:
一、隨機(jī)動(dòng)畫

代碼示例:
<p class="loading">Loading…</p>
@keyframes spin { to { transform: rotate(1turn); } }
@keyframes radius { 50% { border-radius: 50%; } }
@keyframes color { 33% { color: orange; } 66% { color: deeppink; } }
@keyframes width { 50% { border-width: .3em; } }
.loading:before {
content: '';
display: block;
width: 4em;
height: 4em;
margin: 0 auto 1em;
border: 1.5em solid;
color: yellowgreen;
box-sizing: border-box;
animation: 1s spin, .7s radius, 1.1s color, 1.3s width;
animation-timing-function: ease;
animation-iteration-count: infinite;
}
.loading {
margin: auto;
}
二、逐幀動(dòng)畫
需要利用合成好的背景圖,如下:


代碼示例:
<div class="loader">loading...</div>
@keyframes loader {
to {
background-position: -800px 0;
}
}
.loader {
width: 100px;
height: 100px;
margin: auto;
background: url("img/loader.png");
/*隱藏文字*/
overflow: hidden;
text-indent: 999px;
/*這里需要借助css3的控制時(shí)間的屬性steps 階躍函數(shù),還有一個(gè)控制時(shí)間的屬性的函數(shù)是貝塞爾曲線*/
animation: 1s loader infinite steps(8);
}
這里用到了 steps 階躍函數(shù)。
語法:steps(n, start/end)
第一個(gè)參數(shù) n 是一個(gè)正整數(shù),表示階躍次數(shù),
第二個(gè)參數(shù)start或end,表示階躍點(diǎn),
start 表示一開始就先進(jìn)行階躍,end 表示每階段完成后再進(jìn)行階躍,
默認(rèn)值為 end。
階躍時(shí)間函數(shù)如下:


注意點(diǎn):
階躍函數(shù) steps 指的是 @keyframes 中各環(huán)節(jié)之間的時(shí)間變換函數(shù),
它并不是指整個(gè) @keyframes 動(dòng)畫階躍幾次,
如果需要每個(gè)環(huán)節(jié)到下一個(gè)環(huán)節(jié)只階躍一次,可設(shè)置為 steps(1, start/end)。
三、閃爍效果

代碼示例:
<p class="blink1">最普通的閃爍效果:需要借助 steps() 階躍函數(shù),而且必須把關(guān)鍵幀設(shè)置在中間</p>
<p class="blink2">平滑的閃爍效果:讓關(guān)鍵幀設(shè)置在中間50%的位置</p>
<p class="blink3">更加逼真的閃爍效果:需要把循環(huán)的次數(shù)翻倍且要交替出現(xiàn),循環(huán)的時(shí)間設(shè)置為上面的一半</p>
@keyframes blink-smooth1 {
50% {
color: transparent;
}
}
@keyframes blink-smooth2 {
to {
color: transparent;
}
}
p {
padding: 1em;
background: gold;
}
.blink1 {
animation: 2s blink-smooth1 3 steps(1);
}
.blink2 {
animation: 2s blink-smooth1 3;
}
.blink3 {
animation: 1s blink-smooth2 6 alternate;
}
四、緩動(dòng)效果

代碼示例:
<div class="ball">三次貝塞爾曲線</div>
@keyframes bounce {
60%, 80%, to {
-webkit-transform: translateY(400px);
-moz-transform: translateY(400px);
-ms-transform: translateY(400px);
-o-transform: translateY(400px);
transform: translateY(400px);
animation-timing-function: ease;
}
70% {-webkit-transform: translateY(300px);
-moz-transform: translateY(300px);
-ms-transform: translateY(300px);
-o-transform: translateY(300px);
transform: translateY(300px);}
90% {
-webkit-transform: translateY(360px);
-moz-transform: translateY(360px);
-ms-transform: translateY(360px);
-o-transform: translateY(360px);
transform: translateY(360px);
}
}
.ball {
width: 0;
height: 0;
padding: 2.5em;
margin: auto;
border-radius: 50%;
/*at 50% 50% 是指圓心的位置*/
background: radial-gradient(at 30% 30%, #fdd, red);
animation: bounce 3s cubic-bezier(.215, .61, .355, 1) forwards;
}
body {
min-height: 100vh;
background: linear-gradient(skyblue, white 450px, yellowgreen 0);
}
這個(gè)效果是通過另一個(gè)階躍函數(shù):cubic-bezier 函數(shù)。
主要是借用三次貝塞爾曲線來實(shí)現(xiàn)的。
語法:cubic-bezier(x1, y1, x2, y2)
(x1, y1) 表示第一個(gè)控制錨點(diǎn)的坐標(biāo),而 (x2, y2) 是第二個(gè)。
曲線片斷的兩個(gè)端點(diǎn)分別固定在 (0,0) 和 (1,1),前者是整個(gè)過渡的起點(diǎn)(時(shí)間進(jìn)度為零,動(dòng)畫進(jìn)度為零),后者是終點(diǎn)(時(shí)間進(jìn)度為 100%,動(dòng)畫進(jìn)度為 100%)。
固定曲線的兩個(gè)端點(diǎn)并不是唯一的限制。兩個(gè)控制錨點(diǎn)的 x 值都被限制在 [0, 1] 區(qū)間內(nèi)(即我們無法把手柄在水平方向上移出這個(gè)圖形范圍)。這個(gè)限制并不是隨便加上的。
之前如 ease、linear、ease-in、ease-out、ease-in-out 這五個(gè)已有的效果都是 cubic-bezier 實(shí)現(xiàn)的,具體值如下:
ease: cubic-bezier(0.25, 0.1, 0.25, 1.0)
linear: cubic-bezier(0.0, 0.0, 1.0, 1.0)
ease-in: cubic-bezier(0.42, 0, 1.0, 1.0)
ease-out: cubic-bezier(0, 0, 0.58, 1.0)
ease-in-out: cubic-bezier(0.42, 0, 0.58, 1.0)

這個(gè)動(dòng)畫并沒有使用上面五個(gè)已有的動(dòng)畫,需要在 cubic-bezier 上調(diào)試出更加平滑的參數(shù),如例子中的 cubic-bezier(.215, .61, .355, 1) 就是通過此網(wǎng)站調(diào)試的。
五、狀態(tài)平滑的動(dòng)畫

代碼示例:
<div class="state-animation"></div>
@keyframes state {
to {
background-position: 100% 100%;
}
}
.state-animation {
width: 250px;
height: 250px;
background: url("img/timg.jpg");
background-size: auto 100%;
animation: state 10s linear infinite alternate;
/*這里需要?jiǎng)赢嫷腶nimate-play-state屬性*/
animation-play-state: paused;
}
.state-animation:hover, .state-animation:focus {
/*通過動(dòng)畫的播放狀態(tài)來實(shí)現(xiàn)動(dòng)畫的平滑度*/
animation-play-state: running;
}
六、打字動(dòng)畫

代碼示例:
<h1>CSS is awesome!</h1>
@keyframes typing {
from {
width: 0;
}
}
@keyframes caret {
50% {
border-color: transparent;
}
}
h1 {
width: 15ch;
overflow: hidden;
white-space: nowrap;
border-right: .05em solid;
animation: typing 8s steps(15), caret 1s steps(1) infinite;
font: bold 200% Consolas, Monaco, monospace;
}
這里引入了一個(gè)新的 css 單位 ch,它是以 0 的寬度為參考的,在等寬字體中,所有的字體與 0 的寬度是一樣的;如果要加上閃爍的光標(biāo),需要借助右邊框來實(shí)現(xiàn)。
因單行的字符數(shù)量不定,css 維護(hù)不便,為了更易于維護(hù),需要借助 javascript 來實(shí)現(xiàn),如下代碼:
function $$(selector, context) {
context = context || document;
let elements = context.querySelectorAll(selector);
return Array.prototype.slice.call(elements);
}
$$("h1").forEach(function(h1) {
let len = h1.textContent.length, s = h1.style;
s.width = len + "ch";
s.animationTimingFunction = "steps(" + len + "),steps(1)";
});
七、沿環(huán)形路徑平移的動(dòng)畫

代碼示例:
<div class="circular2">
<img src="img/me.jpg" height="960" width="1280" alt="" />
</div>
/*為同一個(gè)元素指定多個(gè)變形原點(diǎn)*/
@keyframes spin2 {
from {
transform: translateY(150px) translateY(-50%)
rotate(0turn)
translateY(-150px) translateY(50%)
rotate(1turn);
}
to {
transform: translateY(150px) translateY(-50%)
rotate(1turn)
translateY(-150px) translateY(50%)
rotate(0turn);
}
}
.circular2 {
margin: 50px auto;
width: 300px;
height: 300px;
background: gold;
border-radius: 50%;
}
.circular2 img {
display: block;
margin: 20px auto;
width: 50px;
height: 50px;
border-radius: 50%;
}
更多動(dòng)畫效果可以參看 animate.css 庫,這里有很多動(dòng)畫,可以參看源碼。