純CSS實現簡單骨骼動畫【實踐】

echa攻城獅 發佈 2020-04-20T13:34:10+00:00

作者:SheldonLaw轉發連結:https://juejin.



作者: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實現過程:

  1. 根據大腿的初始狀態,當前旋轉速度,計算大腿下一幀的位置;
  2. 根據當前大腿的位置和小腿當前的速度,計算小腿下一幀的位置;
  3. ...無限循環...



從這裡可以看出,小腿的位置是依賴大腿的位置的,這就不會出現我們上面的錯位情況。所以說白了,骨骼動畫的特性就是:

關鍵元素帶著子元素一起運動,子元素在此基礎上自己運動。

那麼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

關鍵字: