UI設計師也能輕鬆上手的SVG動態表情

泱泱發表於2017-06-02

先放上效果圖,再說實現方法。

表情變化
表情變化

實現的過程比較簡單,不過大量用到了我在SVG變形動畫裡提到的虛擬曲線c0,0,0,0,0,0,需要補充相關知識的移步juejin.im/post/59195c… 這篇文章。
這個案例因為用到了一個元素疊加多個動畫,所以還是具有代表性的,而且表情元素可以複用(見文章最後)。說一下實現的過程(思路解剖)

1.動靜分離

無論何種形式的SVG動圖,第一步自然離不開我們的“動靜分離大法”。靜態圖分離出來如下:

靜態底圖
靜態底圖

AI裡放到命名為“base”的圖層裡。這個匯出SVG後是可以不用理會的。
這個動效裡,涉及的動效元素有三個,左眼、右眼和嘴巴。表情一共有四種,分別為初始的可愛cute,笑smile,悲傷sad以及暈faint,因此,為了獲得路徑,需要在AI裡依次建立這四個表情的圖層。對應眼睛的動畫有四個,三個表情變化(需要路徑變形動畫完成)外加旋轉動畫。對應嘴巴的動畫為三個變形動畫,如下圖所示。


理清動畫原理,就可以開工了。
基礎程式碼如下:

<g id="base">
…對應靜態底圖的程式碼…
</g>
<g class="emotion">
<path id="left"/>
<path id="right"/>
<path id="mouse"/>
</g>複製程式碼

"left"為左眼路徑(由於悲傷sad的左右眼是對稱關係,所以沒有定義一組動畫多次引用);"right"為右眼路徑;"mouse"為嘴巴路徑。為了方便定義描邊屬性,我把所有的表情元素放到了一個組裡。這樣我就可以通過定義CSS屬性

.emotion path{fill:none;stroke:#615658;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}複製程式碼

來賦給所有的表情元素相同的描邊效果了。

2.第一個動畫的實現

先說眼睛從圓形變成彎彎曲線的過程。首先確定的是,肯定是用了變形動畫。彎彎曲線只需要一段路徑就可以實現,而圓形的組成路徑有四段路徑,因此我們需要改造的就是路徑少的曲線,方法也很簡單,只需要給其增加三個錨點,使其變成四段路徑就可以了。另外圓形路徑也要用剪刀剪成開放路徑。其他要注意的細節調整方法不再詳細說了,變形動畫的三篇文章裡有詳細介紹。

眼睛動畫1實現方法
眼睛動畫1實現方法

@keyframes deformLeft1{
0% {d:path('')}  /*圓形路徑*/
100%{d:path('')} /*笑時的彎彎路徑*/
}  
#left{animation:deformLeft1 1s ease}複製程式碼

這樣就實現了左眼的變形動畫。
這個動畫過程沒有給路徑少的曲線直接增加虛擬曲線是因為試過之後效果不好。
嘴巴實現的過程是直線變曲線的過程,AI直接匯出的直線一定是下面這樣的

<line  x1="" y1="" x2="" y2=""/>複製程式碼

而微微上翹的嘴巴是對應路徑標籤<path>。我們要做的,就是根據直線起點(x1,y1)終點(x2,y2),(水平直線的縱座標y1與y2是等值的)將其轉化成路徑標籤,方法也很簡單,對應d值Mx1,y1c0,0,0,0,(x2-x1),0

嘴巴動畫1實現方法
嘴巴動畫1實現方法

轉化後我們就可以給嘴巴也定義同樣的路徑變形動畫了

@keyframes deformMouse1{
0% {d:path('')} /*直線轉化後的路徑*/
100%{d:path('')} /*微微上翹的嘴巴的路徑*/
}
#mouse{animation:deformMouse1 1s ease}複製程式碼

至此,完成了第一個動畫過程。
在路徑的改造過程中,請用任意一個方法保留未修改的路徑,後面揭曉原因。

3.第二個動畫的實現

在由微笑變傷心的過程中,因為表示傷心的眼睛是兩條直線折線繪製的,這時匯出的標籤是<polyline points=""/>,當然了,如果你對貝塞爾曲線比較熟悉的話,完全可以根據座標值直接來轉化成小c開頭的路徑繪製方法,不熟悉的話就把直線改成帶很少很少很少一點點手柄的曲線吧。
我們在上一個動畫完成時,為了配合圓形,把眼睛彎彎的一條路徑改成了四條,那麼到了這裡怎麼辦?難道再把傷心的眼睛也切成四份,好吧,即使這裡可以這麼操作,那最後暈暈眼睛的螺旋線?那可是N條路徑組成的,難道都要以最終數量最多的路徑為準,加錨點加到手軟抽筋?!
所以說才要保留一份未修改的路徑嘛。我們直接用原始的路徑來進行改造,因為傷心的眼睛是兩條路徑,所以給原始路徑增加一個錨點,使路徑由一條變成兩條就可以啦。無論是路徑上新增了幾個錨點,視覺上無差,所以動畫才能實現無縫拼接。

動畫2眼睛變形動畫實現
動畫2眼睛變形動畫實現

@keyframes deformLeft2{
0% {d:path('')} /*變身兩條路徑的彎彎的眼睛*/
100%{d:path('')}/*悲傷的眼睛*/
}複製程式碼

我們是給一個元素附加多個動畫,語法如下:

#left{animation:deformLeft1 1s ease,deformLeft2 1s ease 1s}複製程式碼

後面依次累加,用逗號,隔開就可以了,因為第一個動畫我設定了1s的完成周期,所以第二段動畫deformLeft2最後的1s表示延遲1s後執行。
之所以沒有采用定義多個關鍵幀的方式來實現多個變形動畫,一個是考慮到最後的螺旋線路徑數量太多,當然,最重要的是每一個變形動畫完成我都採用了ease函式,使每段動畫增加一點停頓感。
對於第二個動畫而言,嘴巴的變形很簡單,就不再贅述了。

4.第三個動畫的實現

這個動畫變形過程路徑的數量差異比較大,當然了,掌握了奇淫技巧的我們怎會被這個問題難住,悲傷的眼睛只有兩段路徑,而螺旋線眼睛足足有七段路徑,差的五段路徑讓我們萬能的虛擬曲線c0,0,0,0,0,0來實現就好啦,so easy!

動畫3眼睛變形動畫實現
動畫3眼睛變形動畫實現

這裡因為圈圈太多,所以描邊粗細stroke-width也順便改一下。

@keyframes deformLeft3{
0% {d:path('')} /*後面補5個c0,0,0,0,0,0*/
100%{d:path('');stroke-width:4}
}複製程式碼

繼續往後面追加定義的動畫deformLeft3咯

#left{animation:deformLeft1 1s ease backwards 1s,deformLeft2 1s ease 1s,deformLeft3 1s ease 2s forwards}複製程式碼

這裡唯一的不同是我加了 forwards,這個屬性值對應的動畫屬性animation-fill-mode,用來定義結束後動畫的狀態,forwards為動畫完成後保持最後一個屬性值。
為什麼要新增這個屬性呢?因為從一開始,我們的眼睛和嘴巴元素在程式碼中是沒有體現的,全憑動畫屬性繪製路徑來新增,而眼睛的下一組動畫為旋轉,如果變成圈圈眼之後不定義結束後動畫狀態,在旋轉動畫時,動畫元素為空。
嘴巴的變形動畫也星對比較簡單,只需要給表示悲傷的向下彎曲的路徑增加錨點,補齊撇嘴對應的路徑數量就好啦。

5.第四個動畫的實現

眼睛的旋轉動畫實現起來很簡單,不過要定義一下旋轉的中心點transform-origin,不定義為預設以畫布左上角原點為中心點。

@keyframes deformLeft4{
0%{transform:rotate(0); transform-origin:}
100%{transform:rotate(360deg); transform-origin:}
}複製程式碼

這個值直接通過AI獲得。

旋轉中心點
旋轉中心點

因為眼睛旋轉的時候,嘴巴是不動的,所以在呼叫嘴巴的最後一個動畫時也要叫上forwards屬性。

#mouse{animation:deformMouse1 1s ease,deformMouse2 1s ease 2s,deformMouse3 1s ease 3s forwards}複製程式碼

好了,以上就是全部動畫的實現過程,那麼做完這麼一套動態變化的表情能用在什麼地方呢?這就是我們“動靜分離大法”玄妙之處,你只需要改一下靜態底圖,就能獲得各種不同效果。而且任意改顏色,簡直爽歪歪。

6.不同底圖的應用

比如我曾經做過一組方形的表情圖示,是下面這種

方形表情圖
方形表情圖

現在,我想讓第一排第二個小心心圖示變身動態表情,只要把我們的動畫效果疊加上,再通過SVG的width、height、viewBox屬性值的設定進行縮放,就得到了下面這個方形表情:

方形表情
方形表情

其他應用就不再一一舉例了,就醬。

相關文章