前言
在
《CSS魔法堂:Transition就這麼好玩》中我們了解到對于簡單的補間動畫,我們可以通過
transition
實作。那到底多簡單的動畫适合用
transtion
來實作呢?答案就是——我們隻需定義動畫起始和結束幀的狀态的動畫。一旦關鍵幀數大于2時,我們必須轉向CSS Animation了。本文為這段時間學習的記錄,歡迎拍磚。
簡單粗暴介紹CSS Animation 規則和屬性
定義關鍵幀動畫
文法:
@keyframes <Animation Name> {
[<Animation Time Offset> {
/* CSS Properties */
}]*
}
示例:
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
注意項:
1.
<Animation Name>
的命名規範
// 命名需要遵循以下規則
const rIsInvalid = /^--|^[0-9]+-|^(?:unset|initial|inherit|none)$/
, rIsValid = /^[0-9a-z-_\\]+$/i
function isValidAnimationName(animationName: string): boolean{
return !rIsInvalid.test(animationName) && rIsValid(animationName)
}
2.
<Animation Time Offset>
取值
0-100%
、
from
,等價與
0%
to
100%
。
3.
<Animation Name>
重複怎麼辦
@keyframes CSS規則不支援層疊樣式,是以當出現多個同名keyframes,那麼僅最後出現的那個有效。
/* 無效 */
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* 生效 */
@keyframes rotate {
from { transform: rotate(90deg); }
to { transform: rotate(-360deg); }
}
4.
<Animation Time Offset>
與@keyframes CSS規則一樣,标準規定相同的關鍵幀不産生層疊,僅最後出現的認定為有效。
但實際上FireFox14+和Chrome均将關鍵幀設計為可層疊的。
@keyframes rotate {
from { transform: rotate(0deg); }
from { background: red; }
/* 上述兩條time offset實際上等價于
* from { transform: rotate(0deg); background: red; }
*/
to {
transform: rotate(360deg);
background: yellow;
}
}
5.
!important
導緻屬性失效
一般情況下使用
!important
會讓CSS屬性獲得最高權重,但在@keyframes下卻會導緻該CSS屬性失效。
@keyframes rotate {
from {
transform: rotate(90deg);
background: red!important; /* background屬性無效 */
}
to { transform: rotate(-360deg); }
}
6.必須提供至少兩個關鍵幀
/* 不會根據緩動函數産生動畫效果,而是在動畫持續時間的最後瞬間移動過去 */
@keyframes move-left{
to {
left: 100px;
}
}
使用動畫
<css-selector> {
animation: <animation-name>
<animation-duration>
<animation-timing-function>
<animation-delay>
<animation-iteration-count>
<animation-direction>
<animation-fill-mode>
<animation-play-state>;
}
.box.rotate {
animation: rotate 10s infinite alternate;
}
子屬性介紹
<animation-name>
,指定通過@keyframes定義的補間動畫名稱。
<animation-duration>
,動畫持續時長,預設為0s。機關為s和ms。
<animation-delay>
,動畫播放延遲,預設為0s。機關為s和ms。
<animation-iteration-count>
,動畫重複播放次數,預設為1,infinite表示無限循環。動畫播放總時長為
<animation-duration>*<animation-iteration-count>
<animation-direction>
,可選值為
normal | reverse | alternate | alternate-reverse
,分别表示動畫播放順序是
從from到to
,
從to到from
從from到to再從to到from
和
從to到from再從from到to
。注意:設定alternate|alternate-reverse時,animation-iteration-count必須大于1才能看到效果
<animation-fill-mode>
none | forwards | backwards | both
,用于設定動畫開始前和結束後是否應用
0%
100%
的樣式對元素上。分别表示
不應用
應用100%的樣式
延遲播放期間應用0%的樣式
0%和100%的樣式均應用
注意:
- 預設情況下(none),動畫結束後會恢複動畫前的樣式;
- 設定backwards時,值大于0才能看到效果。
,可選值<animation-play-state>
,擷取和設定播放狀态。注意:通過這個屬性,我們僅能實作暫停和繼續播放的效果,無法實作重播,更别說回放了running | paused
<animation-timing-function>
,用于設定緩動函數類型,值為
ease | ease-in | ease-out | ease-in-out | linear | step-start | step-end | steps(<integer>, <flag>) | frames(<integer>) | cubic-bezier(<number>,<number>,<number>,<number>)
其中
ease | ease-in | ease-out | ease-in-out | linear | cubic-bezier(<number>,<number>,<number>,<number>)
的效果均為連續漸變的,而
step-start | step-end | steps(<integer>, <flag>) | frames(<integer>)
則為突變效果。下面我們深入了解後者吧。
緩動函數- step
解疑專題
step
step-start
實際上等價于
steps(10, start)
,而
step-end
則等價于
steps(10)
,是以我們隻要了解好
steps(<integer>, <flag>)
即可。
/* 通過設定在一個動畫周期内(<animation-duration>)的平均重新整理幀數,實作突變動效。具體應用有:遊戲精靈行走、打字效果等
* <number_of_steps> - 兩個關鍵幀間的重新整理次數
* <direction> - 方向,可選值為 end | start。
* end為預設值,表示動畫一結束,動畫效果就結束;
* start表示動畫一開始就馬上執行完第一個關鍵幀的效果。
*/
steps(<number_of_steps>, <direction>)
從張旭鑫那偷來的解釋:
start:表示直接開始。也就是時間才開始,就已經執行了一個距離段。于是,動畫執行的5個分段點是下面這5個,起始點被忽略,因為時間一開始直接就到了第二個點:
end:表示戛然而止。也就是時間一結束,目前距離位移就停止。于是,動畫執行的5個分段點是下面這5個,結束點被忽略,因為等要執行結束點的時候已經沒時間了:
另外通過将
<animation-fill-mode>
設定為
forwards
,那麼當
<direciton>
設定為end時,也會顯示(保持)動畫最後一個關鍵幀的樣式。
事件
const target = document.getElementById("target")
target.addEventListener("animationstart", e => {
// 動畫開始時觸發
})
target.addEventListener("animationiteration", e => {
// 每次重複執行動畫時觸發
// 當<animation-iteration-count>為1時,不會觸發。
})
target.addEventListener("animationend", e => {
// 當動畫結束時觸發
})
搞盡腦汁實作重播效果
到這裡我們已經可以通過
@keyframes
定義和應用CSS Animation了,但我們能否擷取對動畫效果更多的控制權呢?如開始、暫停、繼續、重播。通過
<animation-play-state>
我們能輕易實作開始、暫停和繼續的效果,但重播卻沒那麼容易。
function pause (target: HTMLElement):boolean {
const isRunning = target.style.animationPlayState == "running"
if (isRunning) {
target.style.animationPlayState = "paused"
}
return isRunning
}
function play (target: HTMLElement):boolean {
const isStop = target.style.animationPlayState == "paused"
if (isStop) {
target.style.animationPlayState = "running"
}
return isStop
}
function replay (target: HTMLElement, animationClassName: string):void {
// 先移除動畫效果
target.classList.remove(animationName)
// requestAnimationFrame的回調函數會在下一次界面渲染前執行
requestAnimationFrame(_ => {
// 這時動畫的影響還在,是以要等界面渲染完後再重新啟用動畫效果,才能實作重播
requestAnimationFrame(_ => {
target.classList.add(animationName)
})
})
}
總結
CSS3為我們提供了動畫效果,除了提供比Transition更豐富的可控性,比JavaScript更簡易的API,還讓我們可以使用GPU來加速呢^_^
尊重原創,轉載請注明來自:
https://www.cnblogs.com/fsjohnhuang/p/9289618.html^_^肥仔John