使用運動曲線升級 CSS 動畫
已發表: 2022-03-10transition-timing-function
提供了一些預設,例如ease-in
、 ease-out
和ease-in-out
,它們增加了一定程度的平滑度和真實感,但它們非常通用,不是嗎? 如果網絡上的每個動畫都遵循相同的三個計時功能,那該有多無聊?有UI動畫,再有好的UI動畫。 好的動畫會讓你“哇!” ——它光滑、美麗,最重要的是,自然,而不是塊狀、僵硬或機器人。 如果您經常使用 Dribbble 或 UpLabs,您就會知道我在說什麼。
關於粉碎的進一步閱讀:
- 帶有剪輯路徑的 SVG 和 CSS 動畫
- 實用動畫技術
- 使用 SVG 創建“手繪”動畫
- 新的網絡動畫 API
有這麼多出色的設計師創造瞭如此精美的動畫,任何開發人員自然都希望在自己的項目中重新創建它們。 現在,CSS 確實為transition-timing-function
提供了一些預設,例如ease-in
、 ease-out
和ease-in-out
,它們增加了一定程度的平滑度和真實感,但它們非常通用,不是嗎? 如果網絡上的每個動畫都遵循相同的三個計時功能,那該有多無聊?
transition-timing-function
的屬性之一是cubic-bezier(n1, n2, n3, n4)
,您可以在其中傳遞四個數字來創建您自己的計時函數。 在本文的結尾,您將確切地知道這四個數字代表什麼——不過,相信我,想出四個數字來捕捉您在腦海中想像的過渡絕非易事。 但是多虧了cubic-bezier
和Ceasar,您不必這樣做。 這些工具將運動曲線帶入網絡。
動畫師(例如,在 Adobe After Effects 中)主要使用運動曲線來創建高級、逼真的動畫。 使用cubic-bezier
和Ceasar,您可以簡單地操縱曲線的形狀,這四個數字( n1, n2, n3, n4
)將為您填充,這絕對很棒! 儘管如此,要使用並充分利用運動曲線,您需要了解它們的工作原理,這就是我們將在本文中做的事情。 讓我們開始。
了解運動曲線
運動曲線只不過是任何可動畫屬性和時間之間的曲線。 運動曲線定義了在其影響下運行的動畫的速度如何隨時間變化。

讓我們以距離( translateX
)作為動畫屬性的示例。 (該解釋適用於任何其他可動畫屬性。)

如果您有任何物理和基本微積分的經驗,您就會知道從距離-時間圖表中破譯速度非常簡單。 作為時間函數的距離的一階導數是速度,這意味著遵循距離-時間曲線的物體在曲線陡峭的地方速度更快,而在曲線更平坦的地方速度更低. 如果你知道它是如何工作的,那就太好了! 一切就緒,可以跳到下一部分。
現在,我意識到設計和開發是一個多元化的領域,並不是每個人都有相同的背景。 也許上面兩段對你來說都是行話。 別擔心。 我們將繼續前進並理解行話。
考慮下面的紅色框。 讓我們在這裡得到一個小草包,將紅色框稱為“Boxy”; 這樣引用它會更容易。 好的,所以 Boxy 將以線性方式從屏幕的一個邊緣移動到另一個邊緣,我們將分析它的運動。
transition-timing-function
的預設之一是linear
。 為了讓 Boxy 移動,我們所做的就是添加以下類。
.moveForward { transform: translateX(1000px); }
為了控制動畫,我們將設置 Boxy 的transition
屬性如下:
#boxy { width: 200px; height: 200px; background: red; transition-property: transform; transition-duration: 1s; transition-timing-function: linear; }
這是指定transition
的一種非常冗長的方式。 實際上,您幾乎總能找到以簡寫形式編寫的transition
:
#boxy { width: 200px; height: 200px; background: red; transition: transform 1s linear; }
讓我們看看吧。

機器人,不是嗎? 你可以說這個動作感覺機器人,因為它是線性的,這是一個完全合理的答案。 但是你能解釋一下為什麼嗎? 我們可以看到設置linear
會導致機器人運動,但幕後究竟發生了什麼? 這就是我們首先要弄清楚的; 我們將深入了解內部結構並理解為什麼這個動作會讓人感覺機器人、塊狀和不自然。
讓我們從繪製 Boxy 的運動圖開始,看看我們能否獲得一些見解。 我們的圖表將有兩個軸,第一個是距離,第二個是距離。 Boxy 在 1 秒(時間)內覆蓋了 1000 個像素(距離)的總距離。 現在,不要被下面的所有數學嚇到——它很簡單。
這是我們非常簡單的圖表,其中提到了軸。

現在,它是空的。 讓我們用一些數據來填充它。
首先,我們知道在 0 秒時,當動畫尚未開始時,Boxy 處於其初始位置(0 像素)。 1 秒過去後,Boxy 總共移動了 1000 個像素,落在了顯示屏的另一邊。

讓我們在圖表上繪製這些數據。

到目前為止,一切都很好。 但是兩個數據點是不夠的——我們需要更多。 下圖顯示了 Boxy 在不同時間點的位置(這都歸功於我的高速相機)。

讓我們將此數據添加到我們的圖表中。

當然,您可以擁有更多不同時間的數據點(例如,0.375 秒、0.6 秒等),但我們所擁有的足以完成我們的圖表。 通過連接所有點,我們完成了圖表。 擊掌!

很酷,但這告訴我們什麼? 還記得我們開始調查的目的是了解為什麼 Boxy 的直線運動會讓人感覺不自然和機械化嗎? 乍一看,我們剛剛構建的這張圖並沒有告訴我們任何關於它的信息。 我們需要更深入。
記住圖表,讓我們談談速度。 我知道你知道什麼是速度——我只想用數學術語來表達。 事實上,速度的公式是這樣的:

因此,如果一輛汽車在 1 小時內行駛了 100 公里,我們說它的速度是每小時 100 公里。

如果汽車速度加倍,它會在相同的時間間隔(1 小時)內開始行駛兩倍的距離(200 公里),或者換句話說,它將在一半的時間(0.5 小時)內行駛原來的 100 公里距離. 有道理?
同樣,如果汽車將速度減半(即減速一半),它會在相同的時間間隔(1 小時)內開始行駛 50 公里的距離,或者換句話說,它將行駛原來的 100 公里。公里的兩倍時間(2 小時)。
偉大的! 有了這些,讓我們從上次停下的地方繼續。 我們試圖弄清楚距離和時間之間的圖表如何幫助我們理解為什麼 Boxy 的線性運動感覺像機器人一樣。
嘿,等一下! 我們有距離和時間之間的圖表,可以從距離和時間計算速度,不是嗎? 讓我們嘗試計算 Boxy 在不同時間間隔的速度。

在這裡,我選擇了三個不同的時間間隔:一個靠近開始,一個在中間,一個在結束,靠近最終位置。 很明顯,在所有三個間隔中,Boxy 的速度 (s1 = s2 = s3) 完全相同,為每秒 1000 個像素; 也就是說,無論您在上圖中選擇什麼間隔,您都會發現 Boxy 以每秒 1000 像素的速度移動。 這不是很奇怪嗎? 現實生活中的事物不會以恆定的速度移動。 他們慢慢地開始,逐漸加快速度,移動了一會兒,然後再次減速,然後停止,但Boxy突然以每秒1000像素的速度開始,以相同的速度移動,然後以完全相同的速度突然停止。 這就是為什麼 Boxy 的動作感覺機器人和不自然的原因。 我們將不得不改變我們的圖表來解決這個問題。 但在深入研究之前,我們需要知道速度的變化將如何影響在距離和時間之間繪製的圖表。 準備好? 這將會非常好玩。
讓我們將 Boxy 的速度加倍,看看圖形的外觀如何響應變化。 Boxy 的原始速度,正如我們上面計算的,是每秒 1000 像素。 因為我們將速度提高了一倍,Boxy 現在能夠在一半的時間內覆蓋 1000 個像素的距離——即 0.5 秒。 讓我們把它放在圖表上。

如果我們將速度提高三倍呢? Boxy 現在可以在三分之一的時間內(三分之一秒)覆蓋 1000 個像素。


嗯,注意到什麼了嗎? 請注意,當圖形發生變化時,線與時間軸的夾角如何隨著速度的增加而增加。
好吧,讓我們繼續將 Boxy 的速度減半。 將其速度減半意味著 Boxy 將只能在 1 秒內覆蓋 500 個像素(原始距離的一半)。 讓我們把它放在圖表上。

讓我們再把 Boxy 放慢一點,把速度變成原來的三分之一。 Boxy 將能夠在 1 秒內走完原始距離的三分之一。

看到圖案了嗎? 隨著我們增加 Boxy 的速度,這條線變得越來越陡峭,而隨著我們放慢 Boxy 的速度,這條線開始變平。

這是有道理的,因為對於更陡峭的線路,時間上的一點進步會產生更大的距離變化,這意味著更快的速度。


另一方面,對於不太陡峭的線路,時間的較大變化只會產生很小的距離變化,這意味著較低的速度。


通過我們所做的所有更改,Boxy 仍然以線性方式移動,只是速度不同。 然而,憑藉我們新獲得的關於距離隨時間變化如何影響速度的知識,我們可以試驗並繪製一個圖表,使 Boxy 以一種看起來自然而逼真的方式移動。
讓我們一步一步來。 首先,現實生活中的事情一開始很慢,而且速度會慢慢增加。 所以,讓我們這樣做。
在下圖所示的所有迭代中,您會注意到對角處的點保持固定。 這是因為我們沒有改變動畫運行的持續時間,也沒有改變 Boxy 行進的距離。

如果 Boxy 是按照上圖,它會以較慢的速度移動 0.25 秒,因為線從 0 到 0.25 秒開始不那麼陡峭,然後在 0.25 秒後突然切換到更高的速度(原因是圖中的線在 0.25 秒後變得更陡峭)。 不過,我們需要使這種過渡更加順暢; 我們不想要任何角落——畢竟它被稱為運動曲線。 讓我們將該角轉換為曲線。

注意 Boxy 從靜止到逐漸增加速度的平滑過渡。

好的! 接下來,現實生活中的物體在停止之前會逐漸減速。 讓我們更改圖表以實現這一點。 同樣,我們將選擇一個時間點,之後我們希望 Boxy 開始減速。 大約0.6秒怎麼樣? 我已經將過渡的拐角平滑到這裡的曲線。

看看 Boxy 去吧! 更自然,不是嗎?

我們畫的代替角的曲線實際上是許多小線段的集合; 而且,正如您已經知道的那樣,圖表上的線越陡,速度就越高,而線越平坦,速度越慢。 請注意,在圖像的左側,構成曲線的線段如何變得越來越陡峭,導致速度逐漸增加,而在右側逐漸變平,導致速度逐漸降低?

有了所有這些知識,理解運動曲線就變得容易多了。 讓我們看幾個例子。






在 UI 動畫中使用運動曲線
下次您必須為 UI 元素設置動畫時,您將擁有運動曲線的力量。 無論是滑出欄、模態窗口還是下拉菜單,添加適量的動畫並使其看起來流暢自然將大大提高用戶界面的質量。 它將使用戶界面感覺良好。 採取下面的滑出式菜單:
請參閱 CodePen 上 Nash Vail (@nashvail) 的 Pen nJial。
單擊漢堡菜單會從左側進入菜單,但動畫感覺是塊狀的。 CSS 的第 51 行顯示動畫已將transition-timing-function
設置為linear
。 我們可以改進這一點。 讓我們繼續使用三次貝塞爾曲線並創建一個自定義計時函數。
如果您正在閱讀本文,可以肯定地假設您是設計師或開發人員或兩者兼而有之,因此對三次貝塞爾曲線並不陌生; 你很有可能至少遇到過一次。 貝塞爾曲線是一個奇蹟。 它們主要用於計算機圖形中以繪製形狀,並在 Sketch 和 Adobe Illustrator 等工具中用於繪製矢量圖形。 三次貝塞爾曲線如此受歡迎的原因在於它們非常易於使用:只需修改四個不同點的位置,然後創建您需要的曲線類型。
因為我們總是知道動畫對象的初始和最終狀態,所以我們可以修復其中的兩個點。 只剩下兩個點,我們必須修改它們的位置。 兩個固定點稱為錨點,剩下的兩個稱為控制點。

您還記得,當您創建自定義transition-timing-function
時, cubic-bezier
接受四個數字( n1, n2, n3, n4
)。 這四個數字只代表兩個控制點的位置: n1, n2
表示第一個控制點的 x 和 y 坐標, n3, n4
表示第二個控制點的坐標。 因為改變控制點的位置會改變曲線的形狀,從而改變我們的整體動畫,當修改n1, n2, n3, n4
中的任何一個或全部時,結果是相同的。 例如,下圖表示cubic-bezier(.14, .78, .89, .35)
:

(.14, .78, .89, .35)
的三次貝塞爾曲線(查看大圖)這些看似簡單的曲線背後的數學原理令人著迷。
好吧,好吧,讓我們回到我們使用三次貝塞爾曲線的地方:創建一個自定義的transition-timing-function
。 我想要一種動畫,其中菜單非常快速地滑入,然後優雅地放慢速度並結束:

這看起來不錯。 動畫將開始快速然後減速,而不是始終以恆定速度移動。 我只是要從頁面頂部複製cubic-bezier(.05, .69, .14, 1)
並用它替換linear
。
請參閱 CodePen 上 Nash Vail (@nashvail) 的 Pen nJial。
看到不同? 第二次迭代感覺更加自然和吸引人。 想像一下,如果你的 UI 中的每個動畫都遵循一個自然的計時函數。 那該有多好?
正如我們所見,運動曲線一點也不棘手。 它們非常容易理解和使用。 有了它們,您可以將您的 UI 提升到一個新的水平。
我希望您已經了解了運動曲線的工作原理。 如果您經歷了很多嘗試和錯誤以使運動曲線以您想要的方式工作,或者如果您根本沒有使用它們,那麼您現在應該可以根據自己的意願彎曲它們並創建漂亮的動畫。 因為,畢竟,動畫很重要。