【CSS】一文讀懂 Animation 中的時間函數 steps

利用 CSS3 的 Animation 能夠建立動畫,在許多頁面中可以替代 Flash、JS 等,提高頁面加載速度。衆所周知,Animation 有 8 大屬性,以下所述:函數

屬性名 簡介
animation-name 規定須要綁定到選擇器的 keyframe 名稱
animation-duration 完成動畫所花費的時間,以秒或毫秒計
animation-timing-function 規定動畫的速度曲線
animation-delay 動畫開始前的延遲
animation-iteration-count 動畫播放次數
animation-direction 規定是否應該輪流反向播放動畫
animation-play-state 指定動畫是否正在運行或已暫停
animation-fill-mode 當動畫不播放時(動畫完成或動畫延遲),要應用到元素的樣式

以上這 8 個屬性就決定了 Animation 可以實現一個什麼樣的動畫效果。 動畫

本文主要介紹 timing-function中的steps()函數。Animation 在執行動畫時默認以 ease函數進行過渡,ease 會在每一個關鍵幀之間插入補間動畫,因此動畫效果是連貫的。
除了ease函數以外,linearcubic-bezier(貝塞爾曲線)等過渡函數也會爲其插入補間動畫。url

但有的時候某些效果不須要補間,只須要在關鍵幀之間進行跳躍,這時就用到了steps()過渡方式。spa

一、什麼是 steps?

steps()是 Animation 中的一個timing-function函數, 可以實現動畫的階躍式變化,而非兩個狀態間的線性過渡。 
steps() 接收兩個參數:3d

steps ( n, [start | end] )
  • 第一個參數是一個正值,指定動畫分割的段數
  • 第二個參數定義動畫執行開始點,可設定爲 start 或 end,這個值爲可選值,當未傳入參數時默認以 end 方式執行

二、如何使用 steps?

你們都見過很經典的菊花 loading 效果圖,其實現原理很簡單:
一張靜態圖片,而後爲其添加動畫:調試

設定在固定步數內旋轉(rotate) 360 度便可實現 loading 效果,具體實現方式以下:
<div> 
    <img class = "loading-dot-step" src="./loading.png">
</div>

...
.loading-dot-step {
  animation: loading 1s infinite steps(12,start);
}
@keyframes loading {
  0% {transform: rotate(0deg);}
  100% {transform: rotate(360deg);}
}

靜態圖片如圖所示:code

clipboard.png

給上面的靜態圖片添加動畫,steps 設定 12 步完成兩個關鍵幀間的動做軌跡,即從當前狀態旋轉 360 度,實現下面 gif 的動畫效果。orm

菊花loading

除了菊花 loading 效果,很常見的還有線性 loading,其實現方式是:
利用 timing-functionlinear 線性過渡函數,實現圖片的連續旋轉,此時的效果在視覺上就是連續的動畫,以下圖所示:cdn

連續loading

對於兩種 loading 效果圖,第一種爲 steps 方式,第二種爲線性過渡方式。
二者實現原理相似:blog

均在兩個關鍵幀之間將圖片從當前狀態旋轉至 360 度,當 timing-function 設置爲 linear 時,從 0% 到 100% 的狀態變化爲勻速線性變化;
當動做設定爲 steps 時,將從 0 度旋轉至 360 度的整個動畫分爲 12 步執行完,且每步之間是跳躍的,所以出現了經典的菊花 loading 效果。

三、分清 start 和 end

steps 的執行點 start 和 end 是許多人存在疑惑的地方,誤用 start 和 end 可能會出現和理想狀況下不一致的動畫效果,許多人分不清二者的區別在哪裏,下面以幾個簡單的 demo 來輔助理解這兩個屬性值的區別。

steps() 可簡化出 step-startstep-end 這兩個關鍵字。

  • step-start 等同 steps ( 1, start ) ,動畫分紅 1 步,動畫執行時以左側端點爲開始
  • step-end 等同 steps ( 1, end ) ,動畫分紅 1 步,動畫執行時以結尾端點爲開始
<p>一、steps(1, start)</p>
<div class="a box"></div>
<p>二、steps(1, end)</p>
<div class="b box"></div>

...
.a{
  animation:changeColor 4s infinite steps(1, start);
}
.b{
  animation:changeColor 4s infinite steps(1, end);
}
@keyframes changeColor{
  0%{ background-color: red; }
  100%{ background-color: blue; }
}

上述代碼顯示效果以下圖所示:
一、steps(1, start)

clipboard.png

二、steps(1, end)

clipboard.png

代碼可見,二者設定的均爲 1 步執行完動畫,實現將 div 的顏色從紅色變爲藍色,可是咱們看到的結果倒是不一樣的,這就是因爲 startend 兩個屬性的執行點不一樣形成的結果差別。

規範文檔中給出了關於 steps() 的函數圖,以下圖所示:

clipboard.png

對比 steps 函數中的 start 和 end 兩個執行點,由上圖中步數爲 1 的兩圖可見:

  • 整個動做只有一步,在時間爲 0 處,position 設置爲 start 時動畫的第一步已執行完成
  • 相同狀況下,position 設置爲 end ,當時間爲 0 時動畫的第一步還沒有開始

一樣,當步數等於 3 時,肉眼可見的 start 的執行點爲第一步執行結束的位置,end 的執行點則爲第一步還沒有開始的位置 。因爲動畫執行的步數相同但起點不一樣,所以動畫的結束點也不相同,設置爲 start 的狀況下,結束點爲動畫結束的最後一步的狀態,而 end 爲結束前一步的狀態。

爲了更加直觀地展現二者執行的開始點和結束點的區別,本文以橫向座標圖的方式對執行過程進行示意:

clipboard.png

  • 屬性值設置爲 start 時,在動畫開始後,動畫的第一段會立刻完成。以左側端點爲起點,當即跳到第一個 step 的結尾處,而且保持這樣的狀態直到第一步的持續時間結束(後面的每一幀都將按照此模式來完成動畫)。
  • 屬性值設置爲 end 時,在動畫執行的每一幀中,動畫都保持當前狀態直到這一段的持續時間完成,纔會跳到下一步的起點(後面的每一幀都按照這個模式來進行)。

如今能夠解釋上述 demo 中兩個 div 顏色顯示不同的緣由了,對於 steps 屬性值爲 start 的 a-box,進入畫面時動畫的第一階段已經完成,所以咱們不會看到紅色,直接顯示藍色;對於 steps 屬性值爲 end 的 b-box,動畫保持第一幀的狀態直到結束,所以始終顯示爲紅色。

四、什麼時候使用 steps?

並不是全部的動畫都是連續的,對於某些非連續變化的效果就須要用到 steps 來實現。 例如鐘錶秒針階躍式的轉動,或者在動畫中模仿人物或動物的腳印行走效果,再或者利用雪碧圖實現人物跑動的效果等等。下面詳細介紹一下人物跑動效果的實現方式。

人物奔跑 demo
<div class="person"></div>

...
.person {
  background: url('person.jpg') no-repeat;
  background-size: 800%;
  // 動畫名稱 持續時間 運動曲線(steps()分爲幾步)循環次數
  animation: personBlast .8s steps(7) infinite; 
}
@keyframes personBlast {
  0% { background-position: left; }
  100% { background-position: right; }
}

其中 person.jpg 爲人物動做分割的雪碧圖:

人物動做雪碧圖

本文奔跑動做實現方式爲將原始雪碧圖進行按圖形幀數的倍數放大,而後設定steps 爲雪碧圖的幀數減 1(8 幀分爲 7 步執行完),關鍵幀的動做爲從 (from) 雪碧圖左側階躍式跳躍到(to)右側,最終實現下面的跑動效果:

人物奔跑demo

【 注:此奔跑效果的實現方式不盡相同,此處只是其中一種,這樣作是爲了讓你們更好的理解 steps 的應用場景,還有其餘更友好的實現方式歡迎你們一塊兒交流 】

五、請注意 !!!

對於 Animation 的 timing-function 有一個須要引發注意的點,即:

timing-function 的執行位置爲兩個關鍵幀之間,而非整個動畫

此處的 timing-function 指的是本文所講的 steps 函數以及 linear、ease、cubic-bezier 等函數。
這裏仍是經過一個簡單的 demo 來了解這個點。首先看一下下面的動畫效果:

steps做用位置

實現代碼爲:

<div class="test test-a"></div>
<div class="test test-b"></div>

...
.test-a {
  animation: changeColorOne 1s steps(1) infinite;
}
.test-b {
  animation: changeColorTwo 1s steps(1) infinite;
}

@keyframes changeColorOne {
  0% { background-color: red; }
  100% { background-color: blue; }
}
@keyframes changeColorTwo {
  0% { background-color: red; }
  25%{ background-color: blue; }
  75%{ background-color: red; }
  100% { background-color: blue; }
  • 對於 class 爲 test-a 的 div,爲其添加的 changeColorOne 動畫爲 1 秒內完成 0% 及 100% 兩個關鍵幀之間的顏色變化,其執行位置爲 0% 到 100% 之間,所以始終顯示紅色(不設置 start 仍是 end 時默認爲 end)
  • 對於 test-b,changeColorTwo 的關鍵幀有 4 個,所以這時的 steps(1) 的執行位置爲 0% - 25% 兩個關鍵幀中間執行一次、25% - 75% 兩個關鍵幀中間執行一次、75% - 100% 兩個關鍵幀中間執行一次,一共執行3次。因爲執行點設定爲 end, 所以 0% - 25% 顯示紅色,25% - 75% 顯示藍色,75% - 100% 顯示紅色,動畫總體效果即爲上圖 gif 所示。

所以:steps 並不是做用於整個動畫,而是做用於每兩個關鍵幀之間,與動畫的時長、播放次數等都無關,因此整個動畫的執行時間仍是 Animation 中設定的 1s

六、結束語

Animation 時間函數中的 steps() 確實很差理解,可是一旦掌握了它會爲咱們的開發工做帶來很大的效率提高,節省不少調試時間,也能幫助咱們快速定位問題。 但願本文的講解能夠幫助你更好的理解和使用 steps()。感謝閱讀,歡迎互相交流!

相關文章
相關標籤/搜索