設計師的專屬魔法,用SVG動畫重現布林運算的設計過程

泱泱發表於2019-02-19

這是在作圖時突然迸發的靈感(是的,偶爾也會有那麼一瞬間頭腦開竅),作為設計師小夥伴們,平時用的最多的應該是布林運算吧,基礎圖形的加加減減,得到任意的形狀。就不說經典的Apple了,比如網易雲音樂圖示,你如果直接放上這個,似乎沒什麼。

但放上布林運算過程的設計稿(所有基礎圖形的輪廓),瞬間高大上起來,滿滿的設計感。

所以在做向量圖的過程就突然想到如果能用SVG結合CSS3的動效來還原這個設計過程,也不失為一個好玩的效果,當然了,不會那麼巧剛好用到所有的四種運算,只是用動畫過程演示一遍,此為目的。因為自己的底子就很弱,所以選了一個臨摹的圖形,眾位客官湊合看吧。

1.準備工作——圖形分層

每次在做SVG動效之前,都會給自己一點時間思考一下動畫完成的思路,以及用什麼屬性來實現,正所謂多點思考,少點勞作,或者換句話說,“不能用戰術的勤奮來代替戰略的懶惰”。
先放一張成品的效果圖,如下,就是這隻萌萌的小象

AI中做布林運算雖然用路徑查詢器極其方便,且能切割,任意玩,但是修改起來卻沒有PS那麼方便,給做完運算後的調整不是很方便的說。比如十幾甚至更多個形狀的布林運算在PS裡玩起來還算輕鬆,左挪右挪上層下層的調節麼有壓力,在AI裡那要被玩壞了。所以第一步,要在AI裡做好分層。註明一點,這些是要在作圖之前就確定的。
我把小象分成三個部分,身體、頭部和尾巴,目的就是為了減少每個部分的基本形狀的數量。
AI中進行過布林運算後的形狀匯出後是得到的結果的路徑,這就不歡樂了,舉個簡單的例子:

上面兩個圓形,相交之後得到的形狀,匯出後是<path d="">,完全不見兩個圓形<circle>的蹤跡,既然我們是還原過程,過程,就需要把原運算前的路徑保留,怎麼破?在進行運算之前原位複製到新的圖層中唄。以小象的身體為例,我保留了兩個圖層,運算後和運算前的,這些路徑都是我需要用到的。

2.建立圖形過程的動畫

鑑於自己這渣渣一般的水平,圖形加減那一套過程就不拿出來嘚瑟了,還是留著自家珍藏吧,這裡只說如何用動畫表現出來。各位設計師回想一下自己的建立基本形狀的過程,是不是選擇形狀後在畫布進行滑鼠拖動就可以了,嗯,這裡我們主要實現的就是滑鼠拖動的動畫過程。來看下面這張圖(不要給我講你是按著alt鍵巴拉巴拉的,不管,要不這動畫沒法做了 ~~(>_<)~~):

從左上角到右下角的拖動過程就是圖形的建立過程,而且在建立的過程中,圖形是逐漸從無到有,從小到大的。好了,廢話了半天,不不,是拋磚引玉,這就是我們實現建立圖形過程的動畫思路。

@keyframes draw{
0%{transform:scale(0,0);transform-origin:left top}
100%{transform:scale(1,1);transform-origin:left top}
}  
/*通用繪製過程的動畫定義*/複製程式碼

經過分析我們得出,縮放變形transform:scale()是實現這種效果的最佳方案,這裡唯一要注意的是關於變形的基點,前面在涉及旋轉動畫中,更多的定義是transform-origin:center center,也就是以圓心為基點,而這裡定義的是左上角,也就是left top,其實CSS的一些語法真的算是很簡單了,英語入門級。另外這裡對應的left和top的值是相對位置,這也是為什麼能把draw定義成通用的原因。
下面這張圖形虛線部分是為了得到身體部分建立的所有基礎圖形,實色填充的部分即為最後需要的身體部分。

基礎圖形是由5個圓形和1個矩形共同組成的。我進行了標號。

對於身體部分,是4個圓形和1個矩形與1個基礎圓形進行相減得到的。為了讓動畫過程更形象,讓基礎圓形進行了實色填充,其他形狀用虛線來表示。根據上面動畫的定義,先來實現基礎圖形的建立過程,CSS部分如下:

<style>
@keyframes draw{
0%{transform:scale(0,0);transform-origin:left top}
100%{transform:scale(1,1);transform-origin:left top}
} 
#circle0{animation:draw 1s ease;fill:#414c68;}/*基礎形狀用實色填充*/
#circle1{animation:draw 1s ease 1s backwards;}
#circle2{animation:draw 1s ease 2s backwards;}
#circle3{animation:draw 1s ease 3s backwards;}
#circle4{animation:draw 1s ease 4s backwards;}
#rect1{animation:draw 1s ease 5s backwards;}
.sketch{stroke:#c0f1ff;stroke-width:2;fill:none}/*其他形狀用描邊*/
</style>複製程式碼

SVG部分簡化如下(去掉了和形狀尺寸位置相關的屬性定義):

<circle id="circle0"/> <!--基礎形狀-->
<g class="sketch">  <!--其他形狀-->
<circle id="circle1" />
<circle id="circle2" />
<circle id="circle3"/>
<circle id="circle4"/>
<rect id="rect1"/>
</g>複製程式碼

簡單解釋一下,動畫屬性定義那裡拿這個#circle1{animation:draw 1s ease 1s backwards;}為例,第一個1s是繪製時間,第二個1s是延遲時間,為了讓圖形呈現出依次建立的過程,所以延遲時間是遞增的。backwards這個屬性一定要定義,當我們給動畫定義了延遲時,我們需要定義動畫時間之外物件的狀態(animation-fill-mode),backwards表示動畫開始前應用開始屬性值,也就是我們定義的scale(0,0),換句話說,是不顯示的,這裡也可以定義成both,對這個動畫效果而言,沒有區別。
現在看一下動畫效果:

嗯,基本重現了建立了基礎圖形的過程。那麼下一部分來了,怎麼才能過渡到運算之後的形狀呢?

3.運算過程的動畫

在做這個動畫伊始,我想到的是把相減的圖形轉化成蒙版,能行不?絕對能行,但實在是太麻煩了。記得我們還保留了運算後的圖形放到了單獨的圖層中吧?這時,需要它粉墨登場了,然後其他的圖形怎麼辦?集體消失!
關於消失的方法也有很多種,隨便來個順手的就行了,我準備用蒙版。為了實現組合圖形消失以及運算後的圖形出現的過程,不得已,又定義了兩個動畫,其實做到這裡的時候,已經很後悔了,遠不如好好學學AE,在AE裡實現,但自己挖的坑,含著淚也要跳進去再努力爬出來啊,善始善終,硬著頭皮繼續做吧。流著淚補充了下面的動畫定義:

@keyframes skip{
0%{opacity:0}
100%{opacity:1}
} /*這是為要登場的圖形準備的*/
@keyframes combine{
0%{fill:#FFFFFF}
100%{fill:#000000}
}/*這是為要退出舞臺的圖形準備的*/

.skip{animation:skip 1s  6s both; fill:#414c68}
.combine{animation:combine 1s 6s both;}複製程式碼

以及:

<mask id="shade"><rect x="0" y="0" width="800" height="600" id="combine"/></mask> <!--蒙版定義-->
<g mask="url(#shade)">……</g>
<path class="skip" d=""/><!--組合後的形狀-->複製程式碼

<g mask="url(#shade)">是把所有的圖形又組合後,使用這個蒙版。唯一值得欣慰的是skip和combine這兩個動畫可以被複用。
插播一個小知識點,關於利用蒙版的漸隱動畫,是不能用0%{opacity:0} 100%{opacity:1} 然後填充黑色fill:#000000這種表面上看上去是蒙版漸現的方式來實現,是因為當不給蒙版定義顏色時,蒙版會被預設為黑色,因此即使開始定義了透明度為0,也會被當做黑色處理。如果實在要用的話,就套兩層蒙版,一層黑色的透明度改變,下面一層白色實色底。我只截變化的那一部分動畫來看一下:

似乎銜接的還不錯喲。

剩下的工作就是體力活了呃,需要把頭部的動畫和尾巴的動畫補充上,沒有什麼特殊的,延遲的時間別弄錯了就行,這裡就不說了吧。最後得到的統一的動畫是這個樣子的:

與理想中那種滿滿的設計感有差異,不過還好。下面試著來優化一下,上個色吧。

4.顏色填充過程

顏色填充的過程,與這個展示繪製動畫過程沒有什麼毛線關係,就是為了好看!好看!我還能說什麼呢?說什麼顯示填色的過程,鬼,對於怎麼展示漸變填充完美沒有思路,我就利用了一下蒙版,把已經填充好的圖形先用蒙版蓋起來,讓你們看不見看不見,然後在適當的時間,蒙版逐漸移動,露出填充好顏色圖形。為了讓蒙版顯示的效果更加自然,這裡我用漸變色對蒙版進行了填充。圖示如下:

<defs>
<linearGradient id="gradient3"  x1="0" y1="0" x2="0" y2="600">
  <stop offset="0" stop-color="#ffffff"/>
  <stop offset="0.1" stop-color="#000000"/>
</linearGradient>
</defs>    <!--定義的漸變型別-->複製程式碼

最後得到的效果如下:

另外,狠狠的告誡自己,下次再也不做這種費勁巴拉但不酷炫的效果了。

相關文章