給過渡和動畫加上緩動效果是一種常見的手法(好比具備回彈效果的過渡過程)是一種流行的表現手法,可讓界面顯得更加生動和真實:在現實世界中,物體A點到B點每每也是不徹底勻速的css
以純技術的角度來看,回彈效果是指當一個過渡達到最終值時,往回到一點,而後再次回到最終值,如此往復一次或者屢次,並逐漸收斂,最終穩定在最終值。有至關的多JavaScript類庫能夠建立動畫,且內置回彈效果等其餘緩動效果。可是眼下,咱們其實已經不須要藉助腳原本實現過渡和動畫了。不過,在CSS中實現回彈效果的最佳方式是什麼呢?html
咱們的第一感受可能就是使用css動畫,而且設置以下關鍵幀:函數
@keyframes bounce{ 60%,80%,to{transform:translateY(350px);} 70%{transform:translateY(250px);} 90%{transform:translateY(300px);} }
相信咱們都作過這樣的事,可是咱們跑一遍這個動畫,會發現它顯示的及其不真實,主要緣由在於,每當這個小球方向改變時,她得移動過程都是持續加速的,這看起來很不天然。緣由其實就是由於它的調速函數在關鍵幀的銜接都是同樣的
工具
全部的過渡和動畫之間都是跟一條曲線有關的,這條曲線指定了動畫過程在整段時間中是如何推動的
。學習
若是不指定調速函數,就是獲得一個默認值。可是這個默認值
並非咱們想象中的勻速效果,而是:優化
注意,當時間進行到一半時,這個過渡已經推動到80%.動畫
說到調速函數
,咱們很天然聯繫到了css內置的緩動曲線和貝塞爾曲線。spa
不管是在animation/transition
簡寫屬性中,仍是在animation-timing-function/transition-timing-function
展開屬性中,你均可以把這個默認的調速函數顯示指定ease
關鍵字。除了ease外,還有四種內置的緩動曲線,你能夠藉助他們來改變更畫的推動方式.net
從上面四個圖中,咱們很直觀的看出,ease-out
是ease-in
的反向版本。而這一對組合正是實現回彈效果所須要的:每當小球的運動方向相反時,咱們但願調速函數也是相反的
。咱們但願小球下落是加速的(ease-out)
,而彈起向上是減速的(ease-in)
:code
@keyframes bounce{ 60%,80%,to{ transform:translateY(400px); animation-timing-function:ease-out; } 70%{transform:translateY(300px);} 90%{transform:translateY(360px);} } .ball{ animation:bounce 3s ease-in; }
雖然咱們改動不大,可是已經發現回彈效果變得真實起來。不過顯然這五種內置的緩動曲線
是不夠用的,假如咱們這個回彈效果是用來模擬自由落體的,那麼咱們須要一個更高的加速度
和ease的反向版本,又如何獲得呢?
其實全部的這五種曲線都是經過(三次)貝塞爾曲線
來指定的,而CSS的調速函數都是只有一個片斷的貝塞爾曲線
,每一個函數也只有兩個控制錨點,CSS就提供了一個cubic-bezier()
函數,容許咱們指定自定義調速函數。他接受四個參數,分別是兩個控制錨點的座標值,
cubic-bezier(x1,y1,x2,y2)
,曲線的兩個端點固定在(0,0)和(1,1)之間,前者是整個過渡的起點(時間進度0%,動畫進度0%)然後者是整個過渡的終點(時間進度100%,動畫進度100%)。
舉例來講,ease
等同於cubic-bezier(.25,.1,.25,1)
,所以它的反向版本就是cubic-bezier(.1,.25,1,.25)
@keyframes bounce{ 60%,80%,to{ transform:translateY(400px); animation-timing-function:ease; } 70%{ transform:translateY(300PX); } 90%{ transform:translateY(160px); } } .ball{ animation:bounce 3s cubic-bezier(.1,.25,1,.25); }
See the Pen css-animation-easing by okaychen (@okaychen) on CodePen.
咱們能夠藉助cubic-bezier.com的圖形化工具,進行反覆嘗試和優化,從而進一步改寫這個回彈動畫.
通過以上這些知識的學習儲備和練習,相信咱們已經能夠作出很棒的彈跳動畫了.
咱們在文章開始放了一個小球彈跳的gif圖效果,那麼就讓咱們真真正正的動手來寫一下吧!
See the Pen css-animation-easing-practice by okaychen (@okaychen) on CodePen.
假設咱們有一個文本輸入框,每當它被聚焦時,都須要展現一個提示框
咱們有以下結構:
<label> Your username:<input id="username" /> <span class="callout">Only letters,numbers,usrescore(_) and hyphens (-) allowed!</span> </label>
每當用戶聚焦這個文本輸入框時,都會有一個半秒鐘的過渡,可能咱們會完成這樣的代碼
input:not(:focus) + .callout{ transform:scale(0); } .callout{ transition:.5s transform; transition-origin:1.4em -.4em; }
這個過渡沒有任何問題,可是咱們但願它在結尾時能在誇張一點話,顯得更加天然生動,咱們可能會把這個過渡改成一個動畫,而後用上面提到的緩動曲線
@keyframes elastic-grow{ from{transform:scale(0);} 70% { transform:scale(1.1); animation-timing-function:cubic-bezier(.1,.25,1,.25); /*反向的ease*/ } } input:not(:focus) + .callout{ transform:scale(0); } input:focus + .callout{ animation:elastic-grow .5s; } .callout{ transform-origin:1.4em -.4em; }
添加了這個動畫以後,確實發揮了做用。不過這裏咱們其實只是須要一個過渡而已,而咱們本質上卻使用了一個動畫,顯得有些大材小用,有一種殺雞用牛刀的感受,咱們如何只用過渡完成這個效果呢?
這裏咱們就用到了上面提及的調速函數cubic-bezier()
,在這個例子中,咱們但願調速函數先到達110%的程度(至關於scale(1.1)
),而後在過渡回100%,咱們把控制錨點向上移,
這個自定義調速函數在垂直座標上已經超出0~1的區間,最終又回到1,在70%的時間點到達了110%的變形程度的高峯,而後繼續用剩下30%的時間回到它的最終值
整個過渡的推動,很是接近前面的動畫方案,但他僅須要一行代碼就能夠實現整個效果
input:not(:focus) + .callout{ transform:scale(0) } .callout{ transform-origin:1.4em -.4em; transition:.5s cubic-bezier(.25,.1,.3,1.5); }
but,wait...當提示框收縮時,左下角出現的是什麼?其實,當咱們把焦點從輸入框切出去的時候,所觸發的過渡會以scale(1)
做爲起始值,並以scale(0)
做爲最終值,這個過渡仍然會在350ms後到達110%的變形程度。只不過在這裏,110%的變形程度的解析結果並非scale(1.1)
,而是scale(-0.1)
咱們能夠定義關閉狀態的css規則(假如咱們指定普通的ease調速函數)把當前的調速函數覆蓋掉
input:not(:focus) + .callout{ transform:scale(0); transition-timing-function:ease; /*覆蓋cubic-bezier*/ } .callout{ transform-origin:1.4em -.4em; transition:.5s cubic-bezier(.25,.1,.3,1.5); }
再試一試,發現已經關閉提示框已經恢復到咱們設置cubic-bezier()
以前的樣子了,
可是其實咱們仔細觀察發現另外一個問題:提示框的關閉動做明顯要遲鈍一些。
咱們細細想來發現,在提示框展開過程當中,當時間爲50%(250ms)時,它就已經到達100%的尺寸效果了。可是在收縮過程當中,從0%~100%的變化會花費咱們爲過渡所指定的素有時間(500ms),所以感受會慢上通常
而後咱們會想到同時覆蓋過渡的持續時間:能夠用transition-duration
這一屬性,也能夠用transition
這個簡寫屬性來覆蓋全部值,若是選擇後者的話就不須要指定ease了,由於他原本就是transition
的初始值:
input:not(:focus) + .callout{ transform:scale(0); transition:.25s; } .callout{ transform-origin:1.4em -.4em; transition:.5s cubic-bezier(.25,.1,.3,1.5); }
See the Pen css-animation-task by okaychen (@okaychen) on CodePen.
雖然彈性過渡在不少過渡中均可以收到不錯的效果,可是某些時候他產生的效果可能至關糟糕
。典型的反面案例
出如今對顏色屬性
的彈性過渡中。儘管顏色發生彈性過渡可能很是有趣,但這種效果在UI場景中一般是不合適的.
爲了不不當心對顏色設置了彈性過渡,能夠嘗試把過渡的做用範圍限制在某幾種特定的屬性上
,transition不指定時,transition-property
就會獲得它的初始值:all
,這意味着只要是過渡的屬性都會參與過渡。咱們能夠在transition
中設置transform
input:not(:focus){ transform:scale(0); transition:.25s transform; } .callout{ transition-origin:1.4em -.4em; transform:.5s cubic-bezier(.25,.1,.3,1.5) transform; }
參考資料