摘要:方法接受兩個(gè)參數(shù)關(guān)鍵幀和持續(xù)時(shí)間。第一個(gè)參數(shù),關(guān)鍵幀,是一個(gè)對(duì)象數(shù)組,每個(gè)對(duì)象都是動(dòng)畫(huà)中的一個(gè)關(guān)鍵幀。為我們提供了兩種不同的方式設(shè)置緩動(dòng)在我們的關(guān)鍵幀數(shù)組或我們的選項(xiàng)對(duì)象內(nèi)。實(shí)際上,這些緩動(dòng)應(yīng)用在關(guān)鍵幀之間,而不是整個(gè)動(dòng)畫(huà)。
作者:Ollie Williams
原文:CSS Animations vs Web Animations API
在 JavaScript 有一個(gè)原生動(dòng)畫(huà) API 叫 Web Animations API,在這篇文章中簡(jiǎn)稱(chēng)為 WAAPI。MDN 上已經(jīng)有 很好的文檔,而且,Dan Wilson 為此寫(xiě)了 一個(gè)很棒的文章系列。
在本文中,我們一起來(lái)對(duì)比一下 WAAPI 和 CSS 動(dòng)畫(huà)。
關(guān)于瀏覽器支持盡管瀏覽器原生支持仍然有限,但 WAAPI 有一個(gè)全面和強(qiáng)大的 polyfill,使得現(xiàn)在就能在生產(chǎn)環(huán)境使用。
同樣地,可以在 Can I Use 查看瀏覽器兼容性數(shù)據(jù)。然而,這并沒(méi)有提供很好的信息來(lái)支持 WAAPI 的所有子功能。這里有一個(gè)檢查工具:
See the Pen WAAPI Browser Support Test by Dan Wilson (@danwilson) on CodePen.
要想再?zèng)]有 polyfill 的情況下體驗(yàn)所有功能,請(qǐng)使用 Firefox Nightly。
WAAPI 的基礎(chǔ)知識(shí)如果你曾經(jīng)使用 jQuery 的 .animate(),那么應(yīng)該會(huì)覺(jué)得 WAAPI 的基本語(yǔ)法看起來(lái)很熟悉。
var element = document.querySelector(".animate-me"); element.animate(keyframes, 1000);
animate 方法接受兩個(gè)參數(shù):關(guān)鍵幀和持續(xù)時(shí)間。與 jQuery 相比的優(yōu)勢(shì)是,不僅是瀏覽器內(nèi)置,而且性能也更好。
第一個(gè)參數(shù),關(guān)鍵幀,是一個(gè)對(duì)象數(shù)組,每個(gè)對(duì)象都是動(dòng)畫(huà)中的一個(gè)關(guān)鍵幀。看這個(gè)簡(jiǎn)單的例子:
var keyframes = [ { opacity: 0 }, { opacity: 1 } ];
第二個(gè)參數(shù),持續(xù)時(shí)間,指的是想要?jiǎng)赢?huà)持續(xù)多久,在上面的例子中是 1000 毫秒。接下來(lái)看一個(gè)更令人興奮的例子。
用 WAAPI 重新創(chuàng)建一個(gè) animista 的 CSS 動(dòng)畫(huà)這里有一些從 animista 拉取的 CSS 代碼,被稱(chēng)為 slide-in-blurred-top 的入場(chǎng)動(dòng)畫(huà)??雌饋?lái)很漂亮
在 實(shí)際PERF 比這個(gè) GIF 效果好很多。
以下是 CSS 中的關(guān)鍵幀:
0% { transform: translateY(-1000px) scaleY(2.5) scaleX(.2); transform-origin: 50% 0; filter: blur(40px); opacity: 0; } 100% { transform: translateY(0) scaleY(1) scaleX(1); transform-origin: 50% 50%; filter: blur(0); opacity: 1; }
在 WAAPI 中代碼基本相同:
var keyframes = [ { transform: "translateY(-1000px) scaleY(2.5) scaleX(.2)", transformOrigin: "50% 0", filter: "blur(40px)", opacity: 0 }, { transform: "translateY(0) scaleY(1) scaleX(1)", transformOrigin: "50% 50%", filter: "blur(0)", opacity: 1 } ];
可以看出,將關(guān)鍵幀應(yīng)用到需要?jiǎng)赢?huà)的元素上是多么容易:
element.animate(keyframes, 700);
為了簡(jiǎn)單起見(jiàn),只指定了持續(xù)時(shí)間。但是,我們可以使用這個(gè)第二個(gè)參數(shù)來(lái)傳遞更多的選項(xiàng),至少也應(yīng)該指定一個(gè)緩動(dòng)效果。以下是所有可用選項(xiàng)的完整列表,其中包含一些示例值:
var options = { iterations: Infinity, iterationStart: 0, delay: 0, endDelay: 0, direction: "alternate", duration: 700, fill: "forwards", easing: "ease-out", } element.animate(keyframes, options);
加上這些選項(xiàng),我們的動(dòng)畫(huà)將從頭開(kāi)始,沒(méi)有任何延遲,在動(dòng)畫(huà)完成后往返循環(huán)播放。
不爽的是,對(duì)于熟悉 CSS 動(dòng)畫(huà)的人來(lái)說(shuō),一些術(shù)語(yǔ)跟我們習(xí)慣的有所不同。好處是打字會(huì)更快一些!
使用 easing 而不是 animation-timing-function
不是 animation-iteration-count,而是 iterations。如果我們希望動(dòng)畫(huà)永遠(yuǎn)重復(fù),使用 Infinity 而不是 infinite。有點(diǎn)混亂, Infinity 不帶引號(hào)。Infinity 是一個(gè) JavaScript 關(guān)鍵字,而其他值都是字符串。
我們使用毫秒而不是秒,對(duì)于之前寫(xiě)過(guò)許多 JavaScript 的人來(lái)說(shuō),這應(yīng)該是一樣的。(你也可以在 CSS 動(dòng)畫(huà)中使用毫秒數(shù),但很少有人使用。)
我們來(lái)仔細(xì)看看一個(gè)選項(xiàng):iterationStart。
當(dāng)我第一次碰到 iterationStart 有點(diǎn)困惑。為什么要從指定的迭代開(kāi)始,而不是只要減少迭代次數(shù)?當(dāng)使用十進(jìn)制數(shù)時(shí),此選項(xiàng)非常有用。例如,可以將其設(shè)置為 .5,動(dòng)畫(huà)將開(kāi)始一半。要做一個(gè)完整的動(dòng)畫(huà)需要兩個(gè)一半,所以如果迭代次數(shù)設(shè)置為 1,并且將 iterationStart 設(shè)置為 .5,動(dòng)畫(huà)將從一半到動(dòng)畫(huà)結(jié)束播放,然后從動(dòng)畫(huà)開(kāi)頭開(kāi)始,結(jié)束于中間!
值得注意的是,也可以將迭代次數(shù)設(shè)置為小于 1。例如:
var option = { iterations: .5, iterationStart: .5 }
這樣,動(dòng)畫(huà)會(huì)從中間開(kāi)始,一直播放到最后。
endDelay:如果要將多個(gè)動(dòng)畫(huà)串在一起,但是希望在一個(gè)動(dòng)畫(huà)的結(jié)尾和后續(xù)動(dòng)畫(huà)的開(kāi)始之間存在差距,這時(shí) endDelay 就很有用。這是一個(gè)有用的視頻,由 Patrick Brosset 來(lái)解釋。
一個(gè) YouTube 的視頻
緩動(dòng)(easing)在任何動(dòng)畫(huà)中,緩動(dòng)都是最重要的元素之一。WAAPI 為我們提供了兩種不同的方式設(shè)置緩動(dòng) - 在我們的關(guān)鍵幀數(shù)組或我們的選項(xiàng)對(duì)象內(nèi)。
在 CSS 中,如果使用 animation-timing-function: ease-in-out 你可能會(huì)認(rèn)為動(dòng)畫(huà)會(huì)緩慢開(kāi)始,然后緩慢結(jié)束。實(shí)際上,這些緩動(dòng)應(yīng)用在關(guān)鍵幀之間,而不是整個(gè)動(dòng)畫(huà)。這可以對(duì)動(dòng)畫(huà)的感覺(jué)進(jìn)行細(xì)粒度的控制。WAAPI 也提供這種功能。
var keyframes = [ { opacity: 0, easing: "ease-in" }, { opacity: 0.5, easing: "ease-out" }, { opacity: 1 } ]
值得注意的是,在 CSS 和 WAAPI 中,不應(yīng)該傳入最后一幀的緩動(dòng)值,因?yàn)檫@將不起作用。可是很多人會(huì)犯這種錯(cuò)誤。
有時(shí)候,在整個(gè)動(dòng)畫(huà)中添加緩動(dòng)效果更為直觀(guān)。這在 CSS 是不可能的,但現(xiàn)在可以在 WAAPI 中實(shí)現(xiàn)。
var options = { duration: 1000, easing: "ease-in-out", }
可以看到這兩種緩動(dòng)在 CodePen 上的區(qū)別:
點(diǎn)我查看
緩動(dòng) vs 線(xiàn)性值得注意的是 CSS 動(dòng)畫(huà)和 WAAPI 之間的另一個(gè)區(qū)別:在 CSS 中 默認(rèn)值是 ease,而在 WAAPI 默認(rèn)是 linear。 ease 實(shí)際上是 ease-in-out 的一個(gè)版本,當(dāng)你想偷懶時(shí)這是一個(gè)非常好的選擇。同時(shí),線(xiàn)性代表致命的沉悶和無(wú)生命 - 一致的速度看起來(lái)機(jī)械和不自然。它被選為默認(rèn)值,可能因?yàn)樗亲钪辛⒌倪x項(xiàng)。然而,在使用 WAAPI 時(shí),更好是使用緩動(dòng),以免動(dòng)畫(huà)看起來(lái)很乏味和機(jī)械。
性能WAAPI 提供與 CSS 動(dòng)畫(huà)相同的性能改進(jìn),盡管這并不意味著一定就是平滑的動(dòng)畫(huà)。
希望這個(gè) API 的性能優(yōu)化做到,使我們可以避免使用 will-change和 translateZ?成為可能。但是,至少在目前的瀏覽器實(shí)現(xiàn)中,這些屬性在處理性能問(wèn)題方面仍然是有幫助,有必要的。
但是,如果你的動(dòng)畫(huà)有延遲,則無(wú)需擔(dān)心使用 will-change。web animations 規(guī)范的主要作者對(duì) Animation for Work Slack community 提出了一些有趣的建議,希望他不介意我在這里重復(fù):
WAAPI 對(duì)戰(zhàn) CSS 動(dòng)畫(huà)?如果有一個(gè)正向的延遲,不需要使用 will-change,因?yàn)闉g覽器將在延遲開(kāi)始時(shí)進(jìn)行分層,當(dāng)動(dòng)畫(huà)啟動(dòng)時(shí),它將準(zhǔn)備就緒。
WAAPI 為我們提供了一套已經(jīng)在 CSS 中實(shí)現(xiàn)的 JavaScript 語(yǔ)法。然而,它們不應(yīng)該被視為對(duì)手。如果我們堅(jiān)持使用 CSS 完成動(dòng)畫(huà)和轉(zhuǎn)換,那么我們可以在 WAAPI 進(jìn)行動(dòng)畫(huà)交互。
動(dòng)畫(huà)對(duì)象.animate() 方法不僅處理元素的動(dòng)畫(huà),它也返回一些東西。
var myAnimation = element.animate(keyframes, options);
在控制臺(tái)中查看的動(dòng)畫(huà)對(duì)象
如果我們?cè)诳刂婆_(tái)中查看返回值,會(huì)發(fā)現(xiàn)這是一個(gè)動(dòng)畫(huà)對(duì)象。這為我們提供了各種各樣的功能,其中一些是不言自明,比如 myAnimation.pause()。通過(guò)更改 animation-play-state 屬性,我們可以通過(guò) CSS 動(dòng)畫(huà)實(shí)現(xiàn)類(lèi)似的結(jié)果,但 WAAPI 語(yǔ)法比 element.style.animationPlayState = "paused" 更簡(jiǎn)潔。我們也可以通過(guò) myAnimation.reverse() 輕松反轉(zhuǎn)動(dòng)畫(huà),同樣地,跟我們使用腳本更改 CSS 的 animation-direction 屬性相比,稍微有點(diǎn)進(jìn)步。
然而,到目前為止,使用 JavaScript 操作 @keyframe 并不是件容易的的事。即使是重新啟動(dòng)動(dòng)畫(huà)這樣簡(jiǎn)單的事,也是需要一些技巧的,就像 Chris Coyier 先前寫(xiě)過(guò)的那樣。使用 WAAPI,我們可以簡(jiǎn)單地使用 myAnimation.play() ,如果動(dòng)畫(huà)已經(jīng)完成,將從一開(kāi)始就重播動(dòng)畫(huà),或者如果我們暫停播放,則從中間迭代播放動(dòng)畫(huà)。
我們甚至可以輕松地改變動(dòng)畫(huà)的速度。
myAnimation.playbackRate = 2; // speed it up myAnimation.playbackRate = .4; // use a number less than one to slow it downgetAnimations()
這個(gè)方法將返回所有動(dòng)畫(huà)對(duì)象的數(shù)組,包含使用 WAAPI 定義的動(dòng)畫(huà)和 CSS 轉(zhuǎn)換或動(dòng)畫(huà)。
element.getAnimations() // returns any animations or transitions applied to our element using CSS or WAAPI
如果你喜歡使用 CSS 來(lái)定義和使用動(dòng)畫(huà),getAnimations() 允許 API?? 與 @keyframes 結(jié)合使用。你可以繼續(xù)使用 CSS 進(jìn)行大部分動(dòng)畫(huà)工作,然后在需要 API 時(shí)獲得使用 API 的優(yōu)勢(shì)。
即使一個(gè) DOM 元素只使用到一個(gè)動(dòng)畫(huà),getAnimations() 也將始終返回一個(gè)數(shù)組。我們使用那個(gè)單一的動(dòng)畫(huà)對(duì)象來(lái)處理。
var h2 = document.querySelector("h2"); var myCSSAnimation = h2.getAnimations()[0];
我們也可以在 CSS 動(dòng)畫(huà)中使用 web animation API :)
myCSSAnimation.playbackRate = 4; myCSSAnimation.reverse();Promise 和 Event
很多通過(guò) CSS 觸發(fā)的事件,現(xiàn)在我們已經(jīng)可以使用 JavaScript 代碼來(lái)完成: ? animationstart,animationend,animationiteration 和 transitionend。之前經(jīng)常需要監(jiān)聽(tīng)動(dòng)畫(huà)或轉(zhuǎn)換的結(jié)束,以便從 DOM 中刪除應(yīng)用的元素。
在動(dòng)畫(huà)對(duì)象可以使用 WAAPI 來(lái)完成 animationend 或 transitionend 做的事情:
myAnimation.onfinish = function() { element.remove(); }
WAAPI 為我們提供了兩個(gè)選擇:event 和 promise。動(dòng)畫(huà)對(duì)象的 .finished 方法會(huì)返回一個(gè)在動(dòng)畫(huà)結(jié)束時(shí)的 promise。下面這段代碼是上面例子的 promise 版本:
myAnimation.finished.then(() => element.remove())
我們來(lái)看看來(lái)自 Mozilla 開(kāi)發(fā)者網(wǎng)絡(luò)中的一個(gè)稍微復(fù)雜點(diǎn)的例子。Promise.all 接受一個(gè) promise 的數(shù)組,一旦所有 promise 完成才會(huì)運(yùn)行回調(diào)函數(shù)??梢钥闯?,element.getAnimations() 返回的是一個(gè)動(dòng)畫(huà)對(duì)象數(shù)組。我們可以將數(shù)組中的所有動(dòng)畫(huà)對(duì)象 map 到每個(gè)動(dòng)畫(huà)對(duì)象的 .finished上,這樣就獲得需要的 promise 數(shù)組。
在這個(gè)例子中,只有在頁(yè)面上的所有動(dòng)畫(huà)完成后,我們的函數(shù)才能運(yùn)行。
Promise.all(document.getAnimations().map(animation => animation.finished)).then(function() { // do something cool })未來(lái)
本文中提到的功能只是一個(gè)開(kāi)始。從目前的規(guī)范和實(shí)施來(lái)看,未來(lái)會(huì)有一個(gè)很強(qiáng)大動(dòng)畫(huà) API。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/112177.html
摘要:前端日?qǐng)?bào)精選存儲(chǔ)機(jī)制存儲(chǔ)機(jī)制教程手摸手,帶你用擼后臺(tái)系列三實(shí)戰(zhàn)篇個(gè)人文章字號(hào)與行高人人網(wǎng)博客上最好用的更新了掘金基于實(shí)現(xiàn)的一個(gè)截圖小掘金中文用實(shí)現(xiàn)動(dòng)畫(huà)眾成翻譯的裝飾器它們是什么及如何使用掘金之探秘掘金關(guān)于前端頁(yè)面渲 2017-06-14 前端日?qǐng)?bào) 精選 dexteryy/spellbook-of-modern-webdev: A Big Picture, Thesaurus, and ...
摘要:前端日?qǐng)?bào)精選第期正則表達(dá)式回溯法原理入門(mén)教程眾成翻譯在中調(diào)試入門(mén)教程眾成翻譯框架之戰(zhàn)眾成翻譯中文技術(shù)周刊期知乎專(zhuān)欄新特性之命令掘金創(chuàng)建對(duì)象的七種方式中的惰性數(shù)組介紹眾成翻譯跟手轉(zhuǎn)動(dòng)的羅盤(pán)指針掘金和簡(jiǎn)介修仙之路仿音樂(lè)移 2017-06-26 前端日?qǐng)?bào) 精選 【第977期】正則表達(dá)式回溯法原理npm 入門(mén)教程 - 眾成翻譯在 Chrome DevTools 中調(diào)試 JavaScript 入...
推薦 1. JavaScript 在嵌入式設(shè)備與物聯(lián)網(wǎng)中的應(yīng)用現(xiàn)狀 https://auth0.com/blog/javasc... 隨著近年來(lái) Web 的發(fā)展與 JavaScript 的崛起,JavaScript 被應(yīng)用到了許多原本不曾想象到的場(chǎng)景中,從服務(wù)端、工作站、數(shù)據(jù)庫(kù)、桌面環(huán)境到物聯(lián)網(wǎng)設(shè)備中,都可以見(jiàn)到 JavaScript 的身影。而本文則概括了 JavaScript 在不同的嵌入式微...
閱讀 1136·2021-11-24 09:38
閱讀 3242·2021-11-19 09:56
閱讀 2965·2021-11-18 10:02
閱讀 735·2019-08-29 12:50
閱讀 2572·2019-08-28 18:30
閱讀 867·2019-08-28 18:10
閱讀 3675·2019-08-26 11:36
閱讀 2650·2019-08-23 18:23