背景
一日敲代碼的我,得到一個需求:寫一個10秒的倒計時。
用JavaScript定時器麻溜寫完之后,恰好同事勇司機接完水。瞟了一眼,然后湊過來說,這個用CSS3也可以寫,而且一行JavaScript都不用寫。
"一行JavaScript都不用寫,純CSS3就可以寫。CSS3有這么溜的操作!"
''對呀!CSS3 animation當(dāng)中有一個steps(),你上網(wǎng)查一下就知道了!"
"漲姿勢了!趕緊查閱一下!"
animation-timing-function
CSS animation-timing-function屬性定義CSS動畫在每一動畫周期中執(zhí)行的節(jié)奏。可能值為一或多個timing function(數(shù)學(xué)函數(shù))對于關(guān)鍵幀動畫來說,timing function作用于一個關(guān)鍵幀周期而非整個動畫周期,即從關(guān)鍵幀開始開始,到關(guān)鍵幀結(jié)束結(jié)束。
定義于一個關(guān)鍵幀區(qū)塊的緩動函數(shù)(animation timing function)應(yīng)用到改關(guān)鍵幀;
另外,若該關(guān)鍵幀沒有定義緩動函數(shù),則使用定義于整個動畫的緩動函數(shù)。
--MDN Web 文檔
當(dāng)看到這一長串的CSS3屬性,相信有部分童鞋們肯定會陌生這個屬性。因為當(dāng)時我第一眼看到也是一臉問號,表示只熟悉前面的animation。
animation-timing-function其實不記得很正常,這個屬于animation的單獨一個屬性,就好比background-image
這種css屬性大家很少單獨使用,為了書寫代碼方便而更多使用background: url('test.png') center no-repeat;
這種簡寫定義整個背景。
同理在大家對于animation使用過程當(dāng)中,普遍采用animation: move 5s infinite ease both;
這種類簡寫定義整個動畫屬性。這樣的簡寫模式,簡潔、高效何樂不為呢。
借用XXXschool網(wǎng)站上給的使用方法,但是并沒有找到我們想要的 steps()。所以讓我們切換到MDN上面的看一下屬性介紹:
當(dāng)我切換到MDN上面就可以看到語法介紹上面有steps(),而且整體數(shù)量級別也不是一點差別,描述非常詳細(xì)。
PS: 當(dāng)然可能這XXXschool上面更新可能比較慢一點,但是作為日用簡單的查詢還是可以用,深入研究探索還是建議去MDN、W3.org相關(guān)網(wǎng)站上面查閱。
緩動函數(shù)與階梯函數(shù)
總的來說animation-timing-function基本就是分為兩大類型函數(shù):
1、緩動函數(shù):
它描述了在一個過渡或動畫中一維數(shù)值的改變速度。這實質(zhì)上讓你可以自己定義一個加速度曲線,以便動畫的速度在動畫的過程中可以進行改變。緩動函數(shù)指定動畫效果在執(zhí)行時的速度,使其看起來更加真實。
例如現(xiàn)實物體照著一定節(jié)奏移動,并不是一開始就移動很快的。當(dāng)我們打開抽屜時,首先會讓它加速,然后慢下來。當(dāng)某個東西往下掉時,首先是越掉越快,撞到地上后回彈,最終才又碰觸地板。
前端做過渡的動畫大部分都是采用的是這個緩動函數(shù),比較書面一點稱呼就是:立方貝塞爾曲線(cubic Bézier curves)的子集
這里就不繼續(xù)述說緩動函數(shù)了,如果各位小伙伴感興趣推薦兩個網(wǎng)站供小伙伴折騰:
2、階梯函數(shù)
數(shù)學(xué)中,一個實數(shù)函數(shù)被稱為階段函數(shù)(或者階梯函數(shù)),則它可以被寫作:有限的間隔指標(biāo)函數(shù)的線性組合。不正規(guī)的說法是,一個階段函數(shù)就是一個分段常值函數(shù),只是含有的階段很多但是有限。
--wiki百科
看完這些書面化的介紹,學(xué)渣的洪荒之內(nèi)爆發(fā)了,搞一個steps()要這么難搞?
steps()屬性
吃包辣條壓壓驚,查找資料繼續(xù)翻閱文檔。幾番查找,大致整理如下:
首先緩動函數(shù)就像一個人走路一樣,同樣的一段路。他可以迅速的走過去,也可以快速的跑過去,也可以跑一半的距離然后再走過去。所以無論如何控制我們選用那一種運動方式,移動到始終都是靠這個人雙腿一步步移動完成的。
而階梯函數(shù)就像一個失去雙腿,但是卻意外獲得瞬間移動的人。他可以瞬間移動終點,他也可以瞬間移動一半距離,然后再瞬移到終點。所以階梯函數(shù)著重控制的分幾次瞬移完成。
是不是有那么一點感覺,不像剛才那個看到函數(shù)那么的頭疼了!
基本語法:steps(<integer>[, [ start | end ] ]?)
參數(shù)一:integer中文意思就是整數(shù),由此說明第一個參數(shù)是整數(shù)。主要用來指定函數(shù)間隔的數(shù)量,且必須是正整數(shù)(大于0)。
參數(shù)二: 可選 ,接受 start 和 end 兩個值,指定在每個間隔的起點或是終點發(fā)生階躍變化,默認(rèn)為 end。
Keyword values : start-step、end-step
另外相信記憶力比較好的童鞋,這個時候會注意到上述兩個關(guān)鍵詞。
step-start等同于steps(1,start),動畫分成1步,動畫執(zhí)行時為開始左側(cè)端點的部分為開始;
step-end等同于steps(1,end):動畫分成一步,動畫執(zhí)行時以結(jié)尾端點為開始,默認(rèn)值為end。
這時借用W3.org文檔提供的圖表來看,對比wiki的圖表來看,結(jié)合我的說明此時小伙伴們的思路應(yīng)該會更加清晰。
動畫卡通人物:
扯了半天的理論,沒有實際的案例估計小伙伴們也記不住這些東西,那么先來一個栗子!
各大網(wǎng)站大致逛了一下,發(fā)現(xiàn)SegmentFault網(wǎng)站上有位哥們翻譯國外寫teps()里面插入的案例不錯,其中一個例子用來幫助整理和學(xué)習(xí)非常的不錯。
如下一幅圖是由10個小可愛卡通人物組成的,那么我們的任務(wù)就是讓這個卡通人物動起來。
思路分析:
整幅圖是由10個相同大小的矩形組成,每一個矩形都恰好完整包裹卡通人物,一個標(biāo)準(zhǔn)完美的雪碧圖。接下來就將這個雪碧圖作為背景插入展示的DIV盒模型當(dāng)中。(PS:這個DIV盒模型與小矩形的寬高一樣)
之后通過background-position去控制雪碧圖位置定位,例如、0s顯示默認(rèn)第一個動作,然后100ms之后,background-position,瞬間改版了X軸方向,顯示的第二個動作,然后又過了100ms,又展示第三張圖片。依次類推,利用人眼的視覺暫留從而形成動畫的效果。
視覺暫留(Persistence of vision)
現(xiàn)象是光對視網(wǎng)膜所產(chǎn)生的視覺在光停止作用后,仍保留一段時間的現(xiàn)象,其具體應(yīng)用是電影的拍攝和放映。原因是由視神經(jīng)的反應(yīng)速度造成的。是動畫、電影等視覺媒體形成和傳播的根據(jù)。視覺實際上是靠眼睛的晶狀體成像,感光細(xì)胞感光,并且將光信號轉(zhuǎn)換為神經(jīng)電流,傳回大腦引起人體視覺。感光細(xì)胞的感光是靠一些感光色素,感光色素的形成是需要一定時間的,這就形成了視覺暫停的機理。
--摘自網(wǎng)絡(luò)
所以拋開重復(fù)的兼容代碼,10行左右代碼的就能實現(xiàn)一個動畫。
.hi {
width: 50px;
height: 72px; // 矩形的寬高
background-image: url("http://s.cdpn.io/79/sprite-steps.png");
animation: play .8s steps(10) infinite; // 分10步完成0到-500px完成并無限重復(fù)
}
@keyframes play {
from { background-position: 0px; }
to { background-position: -500px; }
}
最終效果圖:
僅僅是代碼上就應(yīng)該比JavaScript要簡潔的多,是不是感覺開啟了新的世界大門!
倒計時案例:
理論加DEMO都看了一遍,那么就開始解決實際工作需求:用steps()函數(shù)敲一個倒計時DEMO出來。
思考點:
通過需求來看,這個10秒倒計時需要控制到10ms的級別.第四位數(shù),每10ms變化一次。然后第三位數(shù)每間隔100ms變化一次,第二位數(shù)字每間隔1s變化一次,第一位數(shù)字不去做變化。
理清楚思路之后就好辦了,接下來code部分了。
在敲代碼之前,先做好一張等比距離的雪碧圖:
PS:因為之前的需求是做成的一張白色透明圖片,而文章背景顏色比較淡。所以臨時截了一個黑色背景圖作為參考
HTML代碼:
<div class="time">
<div class="s10 num"></div>
<div class="s0 num"></div>
<div class="spot">:</div>
<div class="ms0 num"></div>
<div class="ms10 num"></div>
</div>
CSS代碼:
.time {
/*display: none;*/
position: absolute;
top: 2.05rem;
left: 4.73rem;
width: 3.22rem;
height: 0.57rem;
transform: scale(2);
}
.num {
position: absolute;
top: 0.2rem;
width: 0.28rem;
height: 0.37rem;
background: url(img/timeNum.png) no-repeat center;
background-size: cover;
background-position: 0 0;
}
.spot {
position: absolute;
top: 0.06rem;
left: 1.70rem;
color: #fff;
font-size: 24px;
line-height: 0.57rem;
}
.s10 {
left: 0.9rem;
}
.s0 {
left: 1.25rem;
-webkit-animation: sMove 10s steps(10, start);
}
.ms0 {
left: 2rem;
-webkit-animation: sMove 1s steps(10, start) infinite;
}
.ms10 {
left: 2.3rem;
-webkit-animation: sMove 100ms steps(10, start) infinite ;
}
@-webkit-keyframes sMove {
0% {
background-position: -2.80rem 0;
}
100% {
background-position: 0 0;
}
}
最終效果圖:
通過代碼可以看到除去CSS代碼當(dāng)中一樣基本的樣式部分。s0、ms0、ms10這三個元素基本的animation部分基本都是一樣,只是完成的時間以及和循環(huán)的次數(shù)不一樣。是不是感覺不可思議,這么簡單飄逸就搞定了?沒錯,就是那么飄逸!
完成時間差異:
因為雪碧圖有10個數(shù)字,一次只是展示1/10,所以要分10步才能完成一張圖的循環(huán)。那么如同之前的思路分析ms10走一步需要10ms,走完一個循環(huán)10步就需要100ms,ms0就需要1s走完一個循環(huán),s0就需要10s才能走完一個循環(huán)。
循環(huán)次數(shù)
有小伙伴ms10、ms0可能會問,為什么不給定相應(yīng)的循環(huán)次數(shù),而是給無限循環(huán)呢。當(dāng)然給你固定的參數(shù)也是可以,我之所以給這個無限循環(huán)次數(shù),是因為我偷懶不想算他們的循環(huán)次數(shù)。
我更習(xí)慣給s0加一個監(jiān)聽事件webkitAnimationEnd,因為s0沒有指定循環(huán)次數(shù)所以默認(rèn)值為循環(huán)一次,當(dāng)s0動畫執(zhí)行完畢之后,我只需要監(jiān)聽webkitAnimationEnd便開始下一段程序。
小結(jié):
好了!以上就是鄙人對于CSS3動畫當(dāng)中steps()一點簡單理解,權(quán)當(dāng)拋了一下磚頭引大神們的玉。后續(xù)如何用steps()玩出各種花樣就看各位看官自己了!
原創(chuàng)文章,文筆有限,才疏學(xué)淺,文中若有不正之處,再次再次再次歡迎各位啪啪的打臉賜教。(有句話說的好,重要的詞得說三遍。)
PS:對于里面完整blogDemo代碼感興趣的,可以從本人github上閱覽。
源碼demo傳送門地址
我是車大棒,我的目標(biāo)是星辰與大海!