作者:SheldonLaw
轉發連結:https://juejin.im/post/5deb49a251882512302daa92
前言
小夥伴們是否還記得,之前小編也發布了幾篇關於CSS相關文章不妨一起來回顧回顧:
《手把手整理CSS3知識匯總【思維導圖】》
《關於前端CSS寫法104個知識點匯總(一)》
《關於前端CSS寫法104個知識點匯總(二)》
《前端開發規範:命名規範、html規範、css規範、js規範》
《手把手教你55 個提高CSS 開發效率的必備片段》
更多的CSS實現技巧相關文章請見文章底部
1 背景
某天設計師來找我說,「這個心愿牌傻傻地掛在那不好看,加個動效唄,就左右擺動一下就行,很簡單的!」,我一想,行呀,提升用戶視覺體驗,開搞。
十分鐘後,不對呀,這個左右擺動好假,不像現實中風吹的效果。
註:此處加快了動畫的速度和擺動的幅度。
.animate-1 {
animation: swing1 1s ease-in-out infinite;
transform: rotate(-5deg);
transform-origin: top center;
}
@keyframes swing1 {
0% { transform: rotate(-5deg); }
50% { transform: rotate(5deg);}
100% { transform: rotate(-5deg);}
}
複製代碼
冷靜思考,為啥這個擺動會沒有靈魂。於是拿起工卡開始擺動,看看現實中的擺動效果是咋樣的,最後豁然開朗:原來現實中的心愿牌(和工卡同理)在受力的時候,並不會整體擺動,而是會根據節點位置分成幾部分有關聯地擺動,這其實是個簡單的骨骼動畫!那到底怎麼去實現呢?
2 骨骼動畫
關於前端骨骼動畫的實現可以參考《骨骼動畫原理與前端實現淺談》,裡面簡單提及了css和canvas兩種實現方式。這裡將以這個心愿牌擺動動畫為例,和大家一起研究如何使用css來實現。
2.1 分離元素
要讓動畫元素分開運動,首先需要拆分元素。拆分的依據是上面提到的節點,也就是骨骼動畫中所謂的關節。例如這個心愿牌就有兩個關節,分別在牌的上面和牌的下面,於是我們能拆分出3個動畫元素:
2.2 拼接元素
<div>
<!--元素1-->
<div class="item-1"></div>
<!--元素2-->
<div class="item-2"></div>
<!--元素3-->
<div class="item-3"></div>
</div>
複製代碼
這裡看似簡單,但是如果對骨骼動畫不了解的話,會掉到坑裡,上面就是錯誤的示範。為了加深大家的理解,特地挖了一個坑。
2.3 添加動效
在上面的基礎上,我們就可以為每一部分添加不同幅度和方向的擺動動效啦。
<div class="animate-2">
<!--元素1-->
<div class="item-1"></div>
<!--元素2-->
<div class="item-2"></div>
<!--元素3-->
<div class="item-3"></div>
</div>
複製代碼
.animate-2 .item-1 {
/* 設置margin是為了定位,使其部分重疊在一起 */
margin-bottom: -8px;
margin-left: 18px;
position: relative;
z-index: 1;
animation: swing2-1 1s ease-in-out infinite;
transform: rotate(-3deg);
transform-origin: top center;
}
.animate-2 .item-2 {
animation: swing2-2 1s ease-in-out infinite;
transform: rotate(5deg);
transform-origin: top center;
}
.animate-2 .item-3 {
margin-top: -5px;
margin-left: 17.5px;
position: relative;
animation: swing2-3 1s ease-in-out infinite;
transform: rotate(-5deg);
transform-origin: top center;
}
@keyframes swing2-1 {
0% { transform: rotate(-3deg); }
50% { transform: rotate(3deg);}
100% { transform: rotate(-3deg);}
}
@keyframes swing2-2 {
0% { transform: rotate(5deg); }
50% { transform: rotate(-5deg);}
100% { transform: rotate(5deg);}
}
@keyframes swing2-3 {
0% { transform: rotate(-5deg); }
50% { transform: rotate(5deg);}
100% { transform: rotate(-5deg);}
}
複製代碼
大功告成?來看一下效果吧:
我的天,這是啥啊!!!看起來擺動確實要比整體擺動真實,不同元素有不同的擺動幅度和方向。但是錯位了呀。
再繼續冷靜思考,問題出在,骨骼動畫的每一個子動畫都是有關聯的,而我們上面設計的每一個動畫都是獨立的。舉個例子,頂部的紅繩擺動時,會牽引住下面的牌子,導致下面牌子位置發生變化。下面的牌子在位置發生變化的同時,播放自己擺動的動畫,這才是骨骼動畫!
2.4 填坑 - 從js實現骨骼動畫來理解其原理
這裡又給大家推薦個學習資料:《coding-math》系列 - 用數學知識和canvas創造好玩的動畫,其中這一集講解了骨骼動畫的原理,對應的源碼在這裡,因為在油管,為了避免某些同學沒能科學上網看不到,所以以下面的跑步動作為例,講解一下js實現過程:
- 根據大腿的初始狀態,當前旋轉速度,計算大腿下一幀的位置;
- 根據當前大腿的位置和小腿當前的速度,計算小腿下一幀的位置;
- ...無限循環...
從這裡可以看出,小腿的位置是依賴大腿的位置的,這就不會出現我們上面的錯位情況。所以說白了,骨骼動畫的特性就是:
關鍵元素帶著子元素一起運動,子元素在此基礎上自己運動。
那麼js實現中是通過先計算大腿位置,再由大腿位置計算小腿位置來實現聯結的,而css該怎麼實現呢?
2.5 純css實現
回顧最關鍵的地方:關鍵元素帶著子元素一起運動,子元素在此基礎上自己運動。,要實現關鍵元素和子元素一起運動,在css裡面,只要關鍵元素包裹子元素即可!,這就是css實現骨骼動畫的基石。
<div class="animate-3">
<!--運動模塊1-->
<div class="s-1">
<div class="item-1"></div>
<!--運動模塊2-->
<div class="s-2">
<div class="item-2"></div>
<!--運動模塊3-->
<div class="s-3">
<div class="item-3"></div>
</div>
</div>
</div>
</div>
複製代碼
.animate-3 .s-1 {
animation: swing3-1 1s ease-in-out infinite;
transform: rotate(-3deg);
transform-origin: top center;
}
.animate-3 .s-2 {
animation: swing3-2 1s ease-in-out infinite;
transform: rotate(-5deg);
transform-origin: top center;
}
.animate-3 .s-3 {
animation: swing3-3 1s ease-in-out infinite;
transform: rotate(-5deg);
transform-origin: top center;
}
@keyframes swing3-1 {
0% { transform: rotate(-3deg); }
50% { transform: rotate(3deg);}
100% { transform: rotate(-3deg);}
}
@keyframes swing3-2 {
0% { transform: rotate(5deg); }
50% { transform: rotate(-5deg);}
100% { transform: rotate(5deg);}
}
@keyframes swing3-3 {
0% { transform: rotate(-5deg); }
50% { transform: rotate(5deg);}
100% { transform: rotate(-5deg);}
}
複製代碼
這次終於大功告成了。這裡有三個元素,更多元素也是同理的,不斷嵌套即可。
3. 最終動效演示
細心的同學會發現上面實現的骨骼動畫看著也彆扭,歸根結底是各個元素擺動的方向和幅度沒有調節好,這裡附上調整完的效果,用心感受:
.animate-4 .s-1 {
animation: swing4-1 5s ease-in-out infinite;
transform: rotate(-2deg);
transform-origin: top center;
}
.animate-4 .s-2 {
animation: swing4-2 8s ease-in-out infinite;
transform: rotate3d(0, 1, 0, 20deg);
transform-origin: top center;
}
.animate-4 .s-3 {
animation: swing4-3 8s ease-in-out infinite;
transform: rotate(3deg);
transform-origin: top center;
}
@keyframes swing4-1 {
0% { transform: rotate(-2deg); }
50% { transform: rotate(2deg);}
100% { transform: rotate(-2deg);}
}
@keyframes swing4-2 {
0% { transform: rotate3d(0, 1, 0, 20deg); }
50% { transform: rotate3d(0, 1, 0, -20deg);}
100% { transform: rotate3d(0, 1, 0, 20deg);}
}
@keyframes swing4-3 {
0% { transform: rotate(3deg); }
50% { transform: rotate(-3deg);}
100% { transform: rotate(3deg);}
}
複製代碼
4. End
純CSS確實能實現骨骼動畫,但僅限於簡單的場景。在複雜場景中,例如前端遊戲裡面的骨骼動畫,涉及到的節點比較多,用CSS雖然能實現,但效率不高,所以社區有很多從設計工具直接導出可用的骨骼動畫信息,再用js來加載運行的方案,大家感興趣可以Google一下。
本文主要通過簡單的案例來加深大家對骨骼動畫的原理性的認識,至於最後大家用CSS還是用JS來實現,就是「殺雞要不要用牛刀」的問題了。
個人認為,只要屠龍刀在手,用不用已經不重要了。加油,希望大家能在各個方向找到自己的屠龍刀。
推薦關於CSS使用技巧知識點相關文章
《手把手整理CSS3知識匯總【思維導圖】》
《關於前端CSS寫法104個知識點匯總(一)》
《關於前端CSS寫法104個知識點匯總(二)》
《前端開發規範:命名規範、html規範、css規範、js規範》
《手把手教你55 個提高CSS 開發效率的必備片段》
《手把手教你常見的CSS布局方式【實踐】》
《你未必知道的49個CSS知識點》
《手把手教你css 中多種邊框的實現小竅門【實踐】》
《手把手教你深入CSS實現一個粒子動效的按鈕》
《CSS變量實現暗黑模式,我的小鋪頁面已經支持》
《手把手教你利用CSS控制文本溢出截斷省略解決方案合集》
《今天全國哀悼日,手把手教你一段css讓全站變灰》
作者:SheldonLaw
轉發連結:https://juejin.im/post/5deb49a251882512302daa92