在開發者社群中有種錯誤的觀念——認為在web中,CSS動畫是唯一高性能的動畫方式。這使很多開發者放棄基于JavaScript的動畫。是以導緻——(1)強制使用大量樣式表來完成複雜的UI互動,(2)不能很好地支援IE8、9,(3)放棄隻有JS才能完成的完美實體運動效果。
事實證明:基于JavaScript的動畫和基于CSS的動畫一樣快,甚至有時更快。CSS動畫通常是和非常慢的jQuery
$.animate()
比較。但是,JavaScript庫如果能避免像jQuery那樣大量的DOM操作,性能就會非常高。這些庫能比jQuery快20倍。
是以,讓我們來打破一些神話,通過一些動畫執行個體,并在此過程中提高自己的設計技巧。
為什麼是JavaScript
CSS動畫能友善地實作漸變效果,也不需要額外地加載庫。但是它很難支援複雜的效果。代碼不易管理、特性不能滿足需求而導緻失敗。
最終CSS動畫無法完成要求。但JavaScript和大多程式設計語言一樣,支援大量的邏輯控制。JavaScript動畫引擎用事實證明了這點,這裡有些小技巧可以參考:
- cross-browser SVG support(跨浏覽器的SVG)
- physics-based loader animations(實體加載動畫)
- timeline control(時間控制)
- Bezier translations(貝塞爾漸變)
如果你對性能感興趣,可以看看Julian Shapiro 的 “
CSS vs. JS Animation: Which Is Faster?” 和
Jack Doyle 的 “
Myth Busting: CSS Animations vs. JavaScript” 。性能的示範可參考 Velocity 的 “
performance pane” 和 GSAP 的 “
Library Speed ComparisonVelocity 和 GSAP
兩個最流行的JavaScript動畫庫是
Velocity.js和
GSAP。它們都不依賴于jQuery,使得性能提高。
假如你的網站已經用了 jQuery,那就可以像使用 jQuery 一樣使用 Velocity 和 GSAP。例如:
$element.animate({ opacity: 0.5 });
就可以寫成
$element.velocity({ opacity: 0.5 })
。
如果你沒有使用 jQuery 也能使用這兩個庫。但是不能像綁定一系列動畫到JQ元素上那樣,要把元素傳進動畫函數裡,例如:
/* Working without jQuery */
Velocity(element, { opacity: 0.5 }, 1000); // Velocity
TweenMax.to(element, 1, { opacity: 0.5 }); // GSAP
如上所示,在沒有使用JQ的情況下,Velocity 的用法和JQ一樣,把目标元素寫到第一個參數位置,再把其他參數依次往右寫。
GSAP與此不同,采用的是面向對象的API設計,和靜态方法一樣友善。是以你可以完全掌控整個動畫。
在這兩種情況下,你不再是使用一個jQuery的動畫元素對象,而是一個原始的DOM節點。你可以通過
document.getElementByID
、
document.getElementsByTagName
document.getElementsByClassName
document.querySelectorAll
(和jQuery的選擇器很類似)。
不使用jQuery
(注:如果你要學習基本的jQuery
$.animate()
的用法,可以參考Velocity文檔開始的幾段)
querySelectorAll是擺脫jQuery的好武器
document.querySelectorAll("body"); // 擷取body元素
document.querySelectorAll(".squares"); // 擷取所有包含square類的元素
document.querySelectorAll("div"); // 擷取所有div
document.querySelectorAll("#main"); // "main"擷取含有id為main的元素
document.querySelectorAll("#main div"); // 擷取#main裡的div
如上面所示,你可以輕松地把CSS選擇器傳給
querySelectorAll
,它會傳回一個包含所有比對元素的數組。是以,你可以這樣做:
/* 擷取所有div */
var divs = document.querySelectorAll("div");
/* 給所有div加上動畫 */
Velocity(divs, { opacity: 0.5 }, 1000); // Velocity
TweenMax.to(divs, 1, { opacity: 0.5 }); // GSAP
我們不再将元素綁定為jQuery對象,那如何一個接一個地實作動畫呢?
$element // jQuery 對象
.velocity({ opacity: 0.5 }, 1000)
.velocity({ opacity: 1 }, 1000);
在Velocity裡,你隻需一個接一個調用動畫:
Velocity(element, { opacity: 0.5 }, 1000);
Velocity(element, { opacity: 1 }, 1000);
這種方式沒有性能缺陷。要把做動畫的目标元素用變量存儲起來使用,而不是每次都用querySelectorAll查找一次。
(提示:使用Velocity的包,你可以建立自己的多操作的動畫,并給他們取名字,你就可以像Velocity的第一參數一樣操作它。
點選這裡檢視更多。)
這種
one-Velocity-call-at-a-time
的方式有個好處:如果你使用promises,那麼Velocity每次調用後會傳回一個可使用的
promise對象,這非常有用。你可以通過
Jake Archibald的文章了解更多。
GSAP面對對象的方式允許把動畫排入時間線,友善排程和同步控制。這樣就不局限于一個接一個的連結動畫。你可以嵌套時間表、使動畫重疊等。
var tl = new TimelineMax();
/* GSAP預設使用tweens鍊,但你可以在時間線上指定精确的插入點,包括相對偏移 */
tl
.to(element, 1, { opacity: 0.5 })
.to(element, 1, { opacity: 1 });