過渡與動畫 - 逐幀動畫&steps調速函數

寫在前面

上一篇中咱們熟悉五種內置的緩動曲線和(三次)貝塞爾曲線,而且基於此完成了緩動效果.css

可是若是咱們想要實現逐幀動畫,基於貝塞爾曲線的調速函數就顯得有些無能爲力了,由於咱們並不須要幀與幀之間的過渡狀態,就像上篇中所看到的,全部基於貝塞爾曲線的調速函數都會在關鍵幀之間進行插值運算,從而產平生滑的過渡效果。html

這個特性顯然很棒,平滑的效果確實是咱們使用css過渡和動畫所追求的。css3

可是在逐幀動畫的場景下,這種平滑的特性偏偏毀掉了咱們想要實現的逐幀動畫的效果.瀏覽器

逐幀動畫

咱們常常會看到一段卡通影片、一個複雜進度的提示框、一個小loading,
咱們不會單純的選擇一張GIF動畫勝任,由於它的侷限性和短板表現的很明顯.函數

  • GIF圖片所能使用的顏色數量被限制在256色
  • GIF不具備Alpha透明的特性,
  • GIF動畫一旦生成,參數就固定在文件內部,只能經過圖像處理軟件去從新生成.
    在某些場景下,基於圖片的逐幀動畫成了不錯的選擇。

steps()調速函數

寫在前面中提到,咱們不能基於貝塞爾曲線的調速函數完成咱們所須要的逐幀動畫,那麼採用什麼調速函數呢?字體

對,答案就是steps()調速函數,與貝塞爾曲線迥然不一樣的是,steps()會根據你指定的步進數量,把動畫分爲不少幀,並且整個動畫會在幀與幀之間硬切,不會像貝塞爾曲線那樣作插值處理。動畫

對比step(8)、linear以及默認ease的差別

經過上圖咱們能夠很明顯看出steps(8)、linear和ease的區別.網站

其實這種硬切效果是咱們極力避免的,所以咱們也不多聽到關於steps()的討論。在CSS調速函數的世界裏,基於貝塞爾曲線的調速函數就像是被人追捧的白天鵝,而steps()則是旁人惟恐不及的醜小鴨。spa

其實無所謂好與很差,更多的是適合與不適合,咱們都崇拜的貝塞爾曲線在像小"loading"這樣的逐幀動畫中失敗了,而steps()卻展現出咱們想要的效果.prototype

這個想法最初是Simurai在他的博客中推出http://simurai.com/blog/2012/12/03/step-animation,他使用steps()實現拼合圖片的動畫效果.讓人印象深入

codepen中查看效果

See the Pen Steps Animation by simurai (@simurai) on CodePen.


ch單位 - css值與單位第三版

有時候,咱們但願一段爲本字符逐個顯示,模擬出一種打字的效果。這種效果在技術類網站中尤其常見,用等寬字體能夠營造出一種終端命令行的感受.

<h1>CSS is amazing!</h1>
@keyframes typing{
    from{width:0}
}
h1{
    width:7.7em;
    white-space:nowrap;
    overflow:hidden;
    animation:typing 8s;
}

咱們想要模擬出一種打字效果,可是

  • 整個動畫是平滑連貫的,而不是逐字顯示
  • 目前咱們已經使用em指定寬度是7.7,雖然他比像素單位好一些,可是仍然不夠理想,這個寬度爲何是7.7em.

咱們很天然的想到了使用steps()來修復第一個問題,可是不幸的是,咱們所須要的步進數量是由字符的數量來決定的

CSS值與單位(第三版)規範引入了一個新的單位,表示"0"字形的寬度。大多數場景下,咱們沒必要關心"0"字形的寬度到底有多寬,由於在等寬字體中,"0"字形的寬度和其餘全部字形的寬度是同樣的。所以,咱們若是使用ch單位來表示h1的寬度,那取值實際上就是字符的數量:在上面的例子中就是15

@keyframes typing{
    from{ width:0 }
}
@keyframes caret{
    50%{ border-color:transparent }
}
h1{
    width:15ch;
    overflow:hidden;
    white-space:nowrap;
    border-right:0.5em solid;
    animation:typing 6s steps(15),caret 1s steps(1) infinite;
}

可是咱們仍是有些疑問:

  • 這樣的代碼是不易維護的,當更新標題的時候,咱們老是須要根據字符的數量來指定不一樣的寬度樣式和steps()函數,這時候正是JavaScript的用武之地
function $$(selector,context){
    context = context||document;
    var elements = context.querySelector(selector);
    return Array.prototype.slice.call(elements);
}
$$('h1').forEach(function(h1){
    var len = h1.textContent.length,s = h1.style;

    s.width = len + 'ch';
    s.animationTimingFunction = "steps(" + len + "),steps(1)"
})
  • 若是瀏覽器不支持ch單位,咱們該怎麼辦?這時候就須要實現樣式的回退,若是不但願字體出現異常,會選擇補一行em做爲單位的回退樣式

寫在最後

這一篇主要基於steps()函數和ch單位,詳細的比較了steps()調速函數和基於貝塞爾曲線調速函數的區別,雖然steps()調速函數像是旁人惟恐不及的醜小鴨,可是它亦有其獨特的魅力。

參考資料

相關文章
相關標籤/搜索