如何反轉CSS中的貝塞爾曲線

翻譯自《Reversing an Easing Curve》css

首先來看一看我以前寫的一個CSS輪播動畫效果,爲了讓切換時動畫的過渡更加的平滑我在animation-timing-function屬性中並無使用CSS提供的各類關鍵詞,而使用了cubic-bezier(貝塞爾)函數。
圖片描述bash

貝塞爾函數乍一看會讓人困惑摸不着頭腦,但若是使用得當,它能夠爲動畫的用戶體驗增添一種更棒的感受。ide

在構建這個輪播動畫的時候,我意識到當我給一頁添加了顯示的貝塞爾函數時,它前一頁隱藏的貝塞爾函數則是反向的。我以爲咱們分享這篇文章的內容是很是值得的,由於建立一個貝塞爾曲線並反轉它可能看起來很棘手,但實際上很是的簡單。函數

瞭解基礎的easing

首先,Easing這個詞用來描述元素動畫在時間線上的加速與減速節奏。咱們能夠將其繪製成一個圖表,其中x軸是時間,y軸是動畫的進度。linear是沒有加速或減速(一直以相同的速度移動)的圖形,表如今圖上就是一條直線:工具

clipboard.png

非線性的Easing會讓動畫更天然、更逼真。咱們能夠對CSS中的transition和animation應用各類的easing,咱們能夠將這些值設置在transition-timing-function或者animation-timing-function屬性上。總共有五個關鍵字能夠設置:動畫

  • linear – 上面已經介紹了
  • ease-in – 動畫開始時很慢,並隨着它的進行而加速。
  • ease-out – 動畫開始很快,最後減速。
  • ease-in-out – 動畫開始緩慢,中間加速,最後減速。
  • ease – 默認值,與ease-in-out的動畫過程相反。

瞭解cubic-bezier

若是上面介紹的關鍵字值都不適合咱們的動畫,咱們可使用cubic-bezier貝塞爾函數建立自定義的曲線。下面是一個例子:網站

.my-element {
  animation-name: slide;
  animation-duration: 3s;
  animation-timing-function: cubic-bezier(0.45, 0.25, 0.60, 0.95);
}複製代碼

咱們能夠將這些屬性簡寫爲一個,以下所示:ui

.my-element {
  animation: slide 3s cubic-bezier(0.45, 0.25, 0.60, 0.95);
}複製代碼

你會注意到cubic-bezier貝塞爾函數有四個值。這四個值是繪製曲線所需的兩對座標。這些座標表明什麼意思呢?若是你使用過Illustrator,那麼控制曲線大小和方向的向量點對你來講就會很熟悉。這就是咱們用cubic-bezier貝塞爾函數繪製曲線所必須的點。spa

咱們並不須要知道貝塞爾曲線背後的全部數學知識。由於有大佬爲咱們建立了方便的工具,例如LeaVerou的cubic-bezier.com,這個網站中咱們能夠可視化的建立一條貝塞爾曲線並複製它的座標點值。個人輪播效果的貝塞爾曲線就是用這個工具建立的,它看起來是這樣的:翻譯

clipboard.png

在這裏,能夠看到咱們須要的兩個點:cubic-bezier(x1, y1, x2, y2)。

clipboard.png

在正反兩個方向上應用easing

上面的輪播圖中應用了正反兩個方向的動畫 - 單擊左箭頭時,當前項目向右滑出視圖,同時下一個項目向左滑入;若是點擊右箭頭,就會發生相反的狀況。我最初的假設是,能夠簡單地反轉動畫使項目以相反方向滑出,以下所示:

.my-element--reversed {
  animation: slide 3s cubic-bezier(0.45, 0.25, 0.60, 0.95) reverse;
}複製代碼

這裏有一個問題:給animation添加reverse也反轉了easing曲線!因此,如今個人動畫在一個方向看起來很好,但在反方向上是不對的。

下面的演示中,第一個框顯示正方向的動畫,第二個框顯示添加reverse後的狀況。
圖片描述

你能夠看到這兩個動畫的感受徹底不同。第一個盒子在開始加速,而且隨着動畫的進展緩慢地減速,而第二個盒子開始時至關緩慢,而後在中止以前有一個加速的過程。

咱們有兩種方法來解決這個問題:

  1. 建立一個新的keyframe animation來顯示動畫,而後設置爲相同的easing。對於簡單的動畫這樣設置無可厚非,可是若是遇到複雜的動畫該怎麼辦呢?建立反向的動畫須要作更多的工做,並且很容易出錯。
  2. 咱們可使用相同的keyframe animation(並設置animation-direction:reverse)並反轉貝塞爾曲線,這樣就實現了在正反兩個方向上使用同一個easing的效果。這種方法並不難。

反轉貝塞爾曲線,對應在座標軸中就是將總體圖形旋轉180度:

clipboard.png

經過簡單的數學計算就能夠獲得反轉後的點座標,具體方法是:交換兩個座標點,並將每一個值都用1減去。

例如,正方向的座標是:

x1, y1, x2, y2複製代碼

那麼,反方向的座標就經過下面的公式得出:

(1 - x2), (1 - y2), (1 - x1), (1 - y1)複製代碼

在下面的演示中,第三個框是咱們須要的效果:元素向相反的方向滑動,可是它與正方向的動畫曲線是同樣的。
圖片描述

咱們來看看如何計算反向的貝塞爾曲線。

用CSS自定義屬性來計算反向曲線

咱們可使用CSS自定義屬來計算新的曲線!首先將每一個值賦給一個變量:

:root {
  --x1: 0.45;
  --y1: 0.25;
  --x2: 0.6;
  --y2: 0.95;
  
  --originalCurve: cubic-bezier(var(--x1), var(--y1), var(--x2), var(--y2));
}複製代碼

而後咱們可使用這些變量來計算新值:

:root {
  --reversedCurve: cubic-bezier(calc(1 - var(--x2)), calc(1 - var(--y2)), calc(1 - var(--x1)), calc(1 - var(--y1)));
}複製代碼

如今,若是咱們對第一組變量作任何的更改,反向曲線點將會被自動計算出來。爲了在檢查和調試代碼時更容易發現問題,我喜歡將這些新值分配到它們本身的變量中:

:root {
  /* 正向原始值 */
  --x1: 0.45;
  --y1: 0.25;
  --x2: 0.6;
  --y2: 0.95;
  
  --originalCurve: cubic-bezier(var(--x1), var(--y1), var(--x2), var(--y2));
  
  /* 反向計算值 */
  --x1-r: calc(1 - var(--x2));
  --y1-r: calc(1 - var(--y2));
  --x2-r: calc(1 - var(--x1));
  --y2-r: calc(1 - var(--y1));
  
  --reversedCurve: cubic-bezier(var(--x1-r), var(--y1-r), var(--x2-r), var(--y2-r));
}複製代碼

如今剩下的就是將新的曲線應用到反向動畫中:

.my-element--reversed {
  animation: slide 3s var(--reversedCurve) reverse;
}複製代碼

爲了更直觀並切可視化的作到這些,我建立了一個小工具來計算一個貝塞爾曲線的反向值。輸入原始座標值就能夠自動得到反向曲線的值: Reverse cubic-bezier工具 

相關文章
相關標籤/搜索