說說大家都熟悉的網頁動畫技術

發表於2015-12-07

前言

從古代手繪翻書動畫,到膠片電影,再到多張靜態圖合成 gif,
這些都離不開一個術語叫

也就是我們需要繪製每一幀,然後控制一下幀與幀之間的時間間隔。

然而相鄰兩幀之間的變化並不大,重複繪製浪費體力,
幸虧計算機程式碼可以複製貼上,然後修改一下變動的地方就可以了。

等等,好像哪裡不對。

計算機程式碼除了可以複製貼上,還有抽象能力。
我們可以把需要複製貼上的程式碼交給計算機來重複執行。
把需要變動的地方,交給計算機來運算。

而網頁中具備運算能力的只有 JS,其他的就只能是定義一下引數,剩下的就交給瀏覽器了。

這就是 JS 算程式設計,而 HTML、css 不算程式設計的原因。
相關討論,回覆內容+關鍵字#你丫才碼農#

開始

網頁動畫可以通過以下幾種方式實現(gif、flash 除外),

作者知識面有限,如有遺漏,請留言通知我。
相關討論,回覆內容+關鍵字#網頁動畫實現方式#

  • css3 動畫
  • SVG 動畫
  • JS 動畫(包括 css、SVG 的屬性修改實現的動畫)

作者認為 canvas、webGL 只能算是一種繪圖方式。
他們的動畫也都是通過 JS 修改引數來實現的。
相關討論,回覆內容+關鍵字#canvas動畫#

最早 JS 通過 setTimeout() 或者 setInterval() 方法設定一個時間,
來控制幀與幀之間的時間間隔。

  • setTimeout() 直接用跳出來終止下一幀。
  • setInterval() 使用 clearInterval() 來取消週期執行。

但是這樣效果可能不夠流暢,且會佔用額外的資源。
相關討論,回覆內容+關鍵字#你ST設定幾毫秒#
參考:http://www.cnblogs.com/chaogex/p/3960175.html?utm_source=tuicool&utm_medium=referral

後來,有了一個requestAnimationFrame(),讓瀏覽器決定最優幀速率選擇繪製下一幀的最佳時機
requestAnimationFrame()cancelAnimationFrame() 來結束。

所以我們來改變一下思維方式,既然幀與幀之間的時間間隔不用考慮了,那就關心一下變化速率吧。

  • Partial support refers to lacking cancelAnimationFrame support.
  • Supports webkitCancelRequestAnimationFrame rather than `webkitCancelAnimationFrame.

— caniuse.com

好了,動畫講完了,你去找個教程看《canvas 繪圖》?

別介,這才剛剛開始。

慢慢的,我們發現一些簡單動畫只是在修改幾個 css 屬性,而且只是在兩三個狀態之間來回變換。
大量的體力卻浪費在兩個狀態間的補間狀態函式上,而且質量良莠不齊。

來來來,這種事情就交給瀏覽器嘛。

css3 動畫

能夠執行補間狀態的條件是,屬性值能夠轉換成數值,這樣就能參與運算。如:

  • 顏色(color,background-color,border-color…)
  • 長度/大小(width,height,font-size,border-width,border-radius…)
  • 透明度(opacity)
  • 堆疊順序(z-index)你吖補間它有毛用

而不能參與運算就意味著不能拿來補間狀態,也就是沒有中間狀態,如:

  • position(absolute、fixed、relative…)
  • background-image(一個確定的 url)

一拍腦門就能想到,建立一個補間動畫的條件有:

  • 開始狀態
  • 結束狀態
  • 執行時間
  • 補間效果

假如有個方塊,寬度從 10px 變成 100px。

開始狀態呢,在原 css 裡就可以定義了 width: 10px

結束狀態呢,我們可以通過用 JS 直接修改 width 值,或者增加一個 class 選擇器的方式,
或者是 :hover 等其他表示狀態的偽類,讓 width: 100px

而這時,你需要一個補間動畫屬性來宣告 執行時間補間效果
它就是 transition,中文譯作 過渡,就是我所說的補間的意思。

transition 為以下屬性的簡寫

  • transition-property 規定哪個屬性應用過渡
  • transition-duration 執行時間
  • transition-timing-function 補間效果,預設為 ease
  • transition-delay 延遲多少時間開始

參考:http://w3school.com.cn/css3/css3_transition.asp

Support listed is for transition properties as well as the transitionend event. The prefixed name in WebKit browsers is webkitTransitionEnd

— caniuse.com

css3 還提供了一個 animation 屬性來建立更豐富的自定義動畫,而減少 JS 的介入。

比如:

  • 你想一個動畫中擁有多個狀態
  • 每個狀態修改的屬性值較多
  • 迴圈播放
  • 逆向播放
  • 可自動開始,可中途暫停

animation@keyframes 配合使用。

@keyframes 用來定義動畫,animation 則可以多處應用,他們通過一個 name 來連線彼此,
因此 @keyframes 必須要起個名字,而 animation 則有個 animation-name

animation 在應用時,你可以自定義它:

  • animation-duration 執行時間
  • animation-time-function 補間效果,預設是 ease
  • animation-delay 延遲多少時間開始
  • animation-iteration-count 迴圈播放次數
  • animation-direction 是否在下一週期逆向播放
  • animation-play-state 動畫是否暫停,通過它,可以實現是否自動播放。要中途暫停的話,就要修改值,通過偽類或 JS 實現
  • animation-fill-mode 這個屬性倒是有點出乎意料之外,請自行研究使用場景

可見 w3c 規範制定者們考慮到我們要用起來簡單呢,基本上和我們思維方式一致。

實現動畫的多個狀態是在 @keyframes 定義時完成的。

採用 0%~100% 的分割方式,我們就不用在 執行時間 之外考慮時間問題了。

參考:http://w3school.com.cn/css3/css3_animation.asp

Partial support in Android browser refers to buggy behavior in different scenarios.

–caniuse.com

SVG 動畫

css3 動畫屬性只管得住自己的 css 屬性,SVG 繪製的圖形,還得 SVG 自己解決。而對於 SVG 的 css 樣式,一般兩種皆可。

SVG 大大們的思維方式就有點繞了,竟然提供了 5 種動畫 標籤讓我選擇:

  • set 相當於 animate 的 calcMode="discrete",忽略
  • animate
  • animateColor 相當於 animate 的 attributeName="color",忽略
  • animateTransform
  • animateMotion

我們先來看看和 css3 最像的 animate 標籤,擁有的屬性有

  • attributeName 規定哪個屬性應用過渡
  • from 開始狀態
  • to/by 結束狀態,至少出現一個
  • values 多個狀態時,忽略 from/to/by
  • begin 延遲多少時間開始
  • dur 執行時間
  • calcMode,keyTimes,keySplines 自定義補間效果
  • repeatCount,repeatDur 迴圈播放次數/持續時間

額,大概就是這樣,下一個吧。

animateTransform 主要是為了 attributeName="transform"
跟 css3 動畫結合 transform 變換類似,多了一個 type="scale" 屬性用來區分相關引數。

animateMotion 是 SVG 甩 css3 動畫一條街的強大技能,可以讓SVG各種圖形沿著特定的 path 路徑運動。

SVG 動畫比 css 動畫更強大,所以也更復雜。

細分成這 5 類標籤,大概是效能考慮,人工簡單區分一下數值、顏色、變換,可以為計算機省去大量的無用運算。

作者在這裡也沒辦法講的更詳細,估計你也沒看太明白
建議閱讀:http://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/

JS 還有啥用

通過宣告屬性,呼叫瀏覽器來實現的方式,畢竟有限,JS 可以為我們提供無限可能。

通過對比 CSS3 和 SVG 我們也能看出來,要實現的東西越多,我們需要區分、記憶的屬性也越多。
一個複雜動畫使用宣告屬性的方式有可能並沒有通過編寫邏輯來得更爽。看,SVG.js。

在這裡倒是想到了 Grunt 和 Gulp 之爭
相關討論,請回復+關鍵字#不要給我太多配置項#

css3 屬性中宣告的補間效果實在有限,SVG 的 calcMode,keyTimes,keySplines 又略顯複雜,
於是 github 上出現了一大批補間效果倉庫,更有強大者彌補了 CSS3 與 SVG 動畫上各個方面的不足。

https://github.com/bendc/animateplus

  • 簡單小巧,使用簡單
  • 4 大類/29 種補間動畫效果
  • 支援 SVG path 路徑的補間過渡
    • !稍微有點雞肋,path 長度不一致或型別不同時出現動畫混亂
  • !僅支援開始、結束兩個狀態

http://mojs.io/tutorials/easing/path-easing/

無論你定義多少補間效果,都滿足不了所有人的需求,這裡有個 path 路徑補間函式生成器。
var myFunc = mojs.easing.path(path),輸入一個 SVG path,myFunc() 就是你自己的補間函式。

https://github.com/mbostock/d3/wiki/%E8%BF%87%E6%B8%A1

  • 太屌,不進行反面評論
  • 最喜歡它的鏈式操作

https://popmotion.io/guides/introduction-to-animation

  • 一個和 animateplus 一樣容易學的框架
  • !大概是因為主打物理引擎(沒有研究,猜測是這樣),動畫效果有點雞肋
    • 命名很新穎啊,然而並沒有什麼卵用
  • 也提供了很多補間效果,還支援 new ui.Easing(x, y, x, y) 自定義補間效果
    • !自定義補間僅僅是一個簡單貝塞爾曲線,和 mojspath-easing 完全沒有可比性啊
  • !多狀態的過渡是 promise 的寫法,完全沒有 d3.js 的鏈式操作來的爽

作者將會在這裡對比更多 JS 動畫函式庫的使用方法

鳴謝

相關文章