彈簧動效是IOS系統原生自帶的一個效果,如在iPhone上面的照片點開大圖的展示效果就是一個彈簧動畫,如下圖所示:
它有一個彈閃的過程,一大一小交替縮放就像一個彈簧在彈動一樣,而不是以往那種簡單的線性變大。
如果使用CSS的animation-timing-function只是改變運動的速度,不能改變運動的方向。
而自己手動寫CSS模擬這種先變大再變小的效果:
@keyframes spring-show {
0% {
transform: scale(0);
}
90% {
transform: scale(1);
}
/* 先放大一點 */
95% {
transform: scale(1.1);
}
/* 然後再縮回去 */
100% {
transform: scale(1);
}
}複製程式碼
是沒有這種彈性動感的。
因為要實現一個彈簧振動效果,需要有兩個引數,一個是阻尼係數damping ration,另一個是剛度stiffness,阻尼係數決定了衰減的快慢,剛度決定了往返的週期長短。給定這兩個引數和彈簧的始末位移,根據一些物理公式可以推匯出任意時刻彈簧的位移,這個位移就可以當作上面的scale縮放的值,或者是translate、rotate等的值。
那怎麼算呢?大漠在《CSS如何實現彈簧動畫效果》也詳細地討論了這種效果,並寫一個SASS函式實現,不過這種方式生成的CSS普遍比較大,所以我改用了JS實現,原理都是計算一個CSS的keyframes關鍵幀動畫的在1%, 2%, 3%, ..., 100%的時候屬性值應該是多少,然後再動態地插入一個style標籤。這裡借用了一個css spring的庫,這個庫gzip後只有3KB,使用方法如下:
import spring, { toString } from 'css-spring';
const keyframes = spring(
{ scale: 0 }, // from
{ scale: 1 }, // to
// precision表示精度有2位
{ damping: 14, stiffness: 170, precision: 2}
);
const keyframeString = toString(keyframes);
console.log(keyframeString);複製程式碼
生成的CSS如下圖所示:
它會有一個大小的變化過程:0 -> 1 -> 1.1 -> 0.99 -> 1,把這些值畫成一個圖表看起來更加直觀:
可以看到它有一個抖動且週期衰減的過程,實際的效果如下圖所示:
除了放大,縮小也能這樣處理,還可以應用於旋轉,效果如下圖所示:
這個是用下面的程式碼生成的:
const keyframes = spring(
{ rotateZ: 30 }, // from
{ rotateZ: 0 }, // to
{ damping: 14, stiffness: 170, precision: 3}
);複製程式碼
當我們需要藉助animation-delay讓3個星星逐個出現的時候,需要先visibility: hidden隱藏然後再出現,這個時候需要在keyframes裡面新增visibility屬性,如下程式碼所示:
let from = {rotateZ: '30', visibility: 'hidden' },
to = {rotateZ: '0', visibility: 'visible' };
if (from.visibility) {
keyframes['0%'].visibility = from.visibility;
keyframes['1%'].visibility = to.visibility;
// 最後結束animate-fill-mode: forwards使用
keyframes['100%'].visibility = to.visibility;
}複製程式碼
最後生成一個keyframes:
@keyframes spring-rotate {
0% {transform:rotateZ(29.1deg);visibility:hidden;}
1% {transform:rotateZ(27.507deg);visibility:visible;}
/* ... */
100% {transform:rotateZ(0deg);visibility:visible;}
}複製程式碼
再讓每個star星星的animation-delay依次增大:
.star {
visibility: hidden;
animation: spring-rotate .59s linear forwards;
}
.star:nth-of-type(2) {
animation-delay: .15s;
}
.star:nth-of-type(3) {
animation-delay: .3s;
}複製程式碼
這樣就能實現逐個出現的效果了,如下圖所示:
這種彈簧動效能夠增強動感,比普通的單向效果看起來更帶感。
在實際的實現中我寫了一個util,當頁面初始化的時候就生成keyframes,然後插入一個style標籤放在head裡面。因為如果再加上webkit字首,一個keyframes有4KB,10個就有40KB,直接用JS動態計算的方式,會更省空間,靈活性也更強一點。
【人人網招聘中高階前端】
1. 專案背景: 我們在做一個企業級海外的SAAS CRM(客戶管理系統)產品, 前端的技術挑戰很大, 比如在我們的網站讓客戶直接打網路電話(直接打手機那種), 發email, 自動根據使用者場景處理業務等。
2. 技術棧背景: 也是採用比較流行的vue, vuex等框架, 通訊是WebRTC, 訊息分發系統用Google的FCM和蘋果的APN。服務部署在亞馬遜或谷歌雲上。服務全球客戶。
3. 另外因為產品是一個企業級使用者產品所以個方面要求比較高(比如效能,安全,多工處理等)。所以對候選人技術要求比較高,如果您對技術特別在意,那麼我們的空缺提供了很好的才能發揮空間和鍛鍊成長的機會。
【其它文章】實現WebRTC P2P連線