「看相」黑科技:SVG 動畫在 H5 項目中的運用

2021-02-28 網易UEDC


前段時間有個神奇的 H5 刷爆了大家的朋友圈——來自網易雲音樂的《刷臉生成你的12位圖》。它能通過識別你拍攝或上傳的照片幫你「看相」,分析你的各種屬性值,最後為你推薦一首個性歌曲。當然,這裡的「算命結果」僅供娛樂,但面部特徵識別卻是真正的「黑科技」。

我參與了這個項目的動效設計,甚至還動手寫了一部分代碼,和當時正在高考的孩子們一起慘遭數學的蹂躪……通過這篇文章我想和大家分享一些這個 H5 中的動效設計與落地經驗,嗯,主要是用到了 SVG 這個神奇的圖片格式。

☟☟☟還沒玩過的朋友趕緊掃碼體驗一下 ☟☟☟


什麼是 SVG


以下摘自維基百科:

SVG 是 Scalable Vector Graphics(可縮放矢量圖形) 的縮寫,相對於JPEG、PNG和GIF等格式,它具有如下特點:

可以包含矢量和位圖,矢量部分不會因為適配縮放而損失畫質。

圖像文件可讀(可以用文本編輯器編輯),易於修改和編輯。

支持動畫,與現有技術可以互動融合。例如,SVG 技術本身的動態部分(包括時序控制和動畫)就是基於 SMIL 標準。另外,SVG 文件還可嵌入 JavaScript(嚴格地說,應該是ECMAScript)腳本來控制SVG對象。

SVG 圖形格式可以方便的創建文字索引,從而實現基於內容的圖像搜索。

SVG 圖形格式支持多種濾鏡和特殊效果,在不改變圖像內容的前提下可以實現位圖格式中類似文字陰影的效果。

SVG 圖形格式可以用來動態生成圖形。例如,可用 SVG 動態生成具有交互功能的地圖,嵌入網頁中,並顯示給終端用戶。

本文將主要介紹 SVG SMIL 動畫。SMIL 全稱是 Synchronized Multimedia Integration Language,即「同步多媒體集成語言」,簡單來說能利用 SVG 內部元素的設置來驅動動畫。另外常用的 SVG 動畫手段還有 CSS 結合 SVG、JavaScript 結合 SVG 做動畫,限於篇幅本文不做涉及。

我在之前的項目《網易雲音樂陪你溫暖同行》(網易雲音樂 2017 年終總結)中就用到了 SVG 動畫:

微信公眾號只能放 GIF,SVG 版本請掃碼體驗

這三組動畫都是周期很長的循環動畫,其中星球和落葉的動畫佔頁面的面積都還不小,需要保證一定的清晰度。如果按照傳統做法做成 GIF 或者 PNG 序列幀要麼體積大,要麼會很卡頓(實際上文章中展示的 GIF 圖就是為了減小體積壓縮得卡頓了,SVG 版本是絲般順滑的),而如果我們使用 SVG 來實現,就只需要很小的體積,動畫卻能清晰流暢,還不用特意為做成循環妥協效果。



用「代碼」作圖


可能很多設計師都導出過靜態的 SVG 資源給開發,工具方面我們可以在 Adobe Illustrator、Sketch 等工具中繪製好後直接導出,甚至我們打開記事本之類的文本編輯器都能手寫一個。沒錯,SVG 就是一段段「代碼」,通過瀏覽器讀取並顯示為圖片或者動畫。下面就是一段簡單的 SVG 「代碼」:

<svg width="1000" height="1000" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <circle cx="500" cy="350" r="300" fill="red"></circle>
  <text x="280" y="750" fill="blue" font-size="80">
    這是一個圓
  </text>
</svg>

將它複製到記事本或者其他文本編輯器, 保存為 .svg 格式,再用 Chrome 等瀏覽器打開,將能看到

(根據作業系統不同字體可能不同)

不要被這些「代碼」嚇到,我們稍微修改一下,就能直觀感受到它們對圖像有怎樣的影響。看這行:

<circle cx="500" cy="350" r="300" fill="red"></circle>

很明顯這一行是控制那個圓的,而「cx」、「cy」控制圓的位置,「r」控制圓的半徑,「fill」控制圓的填充顏色(可以用「red」,「blue」等單詞表示顏色,但最好使用「#FF0000」這樣的十六進位色值來精確控制)。

嘗試改變這些值,保存,再在瀏覽器刷新查看,就能看到改動後的效果。

<circle cx="400" cy="550" r="100" fill="#00BFFF"></circle>

而圓只是基本圖形之一,如果我們想畫一條線,可以這麼寫:

<path stroke="red" stroke-width="5" d="M300,790 L700,790"></path>

把它加在 <circle> 後面

<circle …… ></circle>
<path stroke="red" stroke-width="5" d="M300,790 L700,790"></path>
<text ……

可以看到我們在「這是一個圓」這幾個字下畫了一條紅線:


這行裡,「stroke」、「stroke-width」分別控制線段的顏色和粗細,比較難懂的是「d="..."」裡的內容。其實是這麼個意思:

"M300,790 L700,790" = "Move to (300,790) Line to (700,790) ",也就是「從(300,790)這個位置,畫一條直線到(700,790)」,表示位置的是坐標(x,y)。

這樣我們就可以可以畫兩個圓,然後把他們用線連起來。

<circle cx="100" cy="550" r="50" fill="#00BFFF"></circle>
<circle cx="500" cy="350" r="50" fill="#00BFFF"></circle>
<path stroke="#00BFFF" stroke-width="5" d="M100,550 L500,350"></path>

OK,現在我們再回憶一下《刷臉生成你的12位圖》項目裡,當照片被掃描成功後出現在人臉上的圖形,其實就是由這最基本的點和線組成。

那麼這些點的位置是如何確定的呢?「黑科技」來自網易人工智慧事業部,通過深度學習技術檢測圖片中人臉的面部特徵點,返回每個特徵點的坐標。通過計算這些坐標間的關係我們可以得出一些數據,「算命結果」就是根據這些數據進行差異化呈現。感興趣的可以到 網易人工智慧官網的演示頁面 來試試:

https://ai.163.com/#/m/services/intVision/face/anchor

上傳帶人臉的照片,或者粘貼圖片網址,點擊「提交」,就會生成特徵點。左邊是在照片上顯示點的位置,右邊就是各個點的坐標等數據了。

如果掃描正常,點的數量是固定的,每個點編號如下:

設計師再在這個基礎上做設計,根據編號細調每個點的顏色、粗細、透明度等。細心的你可能已經發現了,我們最終用到的點比實際可檢測出的點要少,因為實際在手機上顯示的時候人臉所佔面積不大,不需要太多的點;但不知你有沒有看出來,有的點並不是直接檢測出來的,而是算出來的。

如下圖,點69 是「點1和點2的連線」與「點40和點37的連線」的交點,點70 是「點17和點16的連線」與「點43和點46的連線」的交點,而 點71 是「點40和點43的連線」的中點。

為什麼要計算這幾個點?這樣增加了設計的靈活度,更能直觀的顯示「下頜角」、「三庭五眼」之類的指標——我們「看相」還是很嚴謹的!

再看看另一個動畫,從下巴擴散出去的綠線:

以其中一條線為例,從 點9(記作 p9)出發作一條過 點8(記作 p8)的「射線」,在射線上取一點 p0,令線段「p9-p8」 長度為 a,「p8-p0」長度為 b,由於 a 在每張圖上是確定的,我們控制好 a:b 的比例 ,將 p9 和 p0 連起來,就能得到一條圖中的綠線了,再如法炮製其它幾組。這條線的比值是 a:b = 1:3 ,也就是 b 是 a 的3倍長度,其他的線根據視覺效果調整比例即可。

再來看看「五眼」——這個算起來就有點複雜了。分別過點1、點37、點40、點43、點46和點17作過「點69與點70連線」的垂線,這樣就得到6個綠點。這些垂線的下端分別從點5、點6、點8、點10、點12、點13與之的垂線處截斷,而上端則使用前一個圖裡從下巴擴散出去的綠線的算法,基於下端已知線段長度,通過比例控制向上延伸的程度。

有沒有想起高考被數學支配的恐懼?幸好這不是考試,我們有萬能的網際網路……

利用 WolframAlpha 網站解方程,你看出來是計算哪個部分的方程了嗎?

http://www.wolframalpha.com


讓 SVG 動起來

好了,知道了圖怎麼「畫」,下一步就讓他們動起來!動畫就是在元素中插入 animate 相關語句,例如:

<animate attributeName="opacity" from=" 1" to="0" begin="0s" dur="1s" repeatCount="indefinite"></animate>

就是在 1 秒內讓這個元素的不透明度從1變為0,並一直重複這個動畫。

還有一種寫法是:

<animate atrribute="opacity" values="1;0" begin="0s" dur="1s"  repeatCount="indefinite"></animate>

這裡「values="1;0"」等價於「from=" 1" to="0"」,但「from…to」方式只能指定初始和結束狀態的值,「values」方式能有更多變化,比如我們寫成「values="1;0;1"」就是在「1秒內」讓這個元素的「不透明度」從 1 變為 0 再變回 1,完成一個循環。如果寫成「values="1;0;1;0;1;0;1;0;1;0;1"」就是一個閃爍動畫。

這一段「代碼」應該放到哪裡呢?

回顧一下我們的 SVG 「代碼」,可以發現他是這麼個結構:

<svg aaa="bbb" ccc="ddd"……>
  <xx元素 eee="fff" ……></>
  <yy元素 ggg="hhh" ……></>
</svg>

這裡用的是「XML」語法,其中以 < 開頭,以 > 結尾的東西是一個「標籤」。如果是 <……> 這種格式的是「開始標籤」; </……> 是「結束標籤」;還有一種  <……/>  是「空元素標籤」。

每個「開始標籤」後都必須跟一個「結束標籤」,開始標籤和結束標籤之間可以插入內容, <……>內容</……> ,內容可以是文字(例如例子裡的「這是一個圓」)也可以是其他標籤,或則混合在一起。每一個組「開始標籤」「結束標籤」加上其中的內容我們稱之為一個「元素」,如果內容為空,<……></……> 可以寫成 <……/> 即「空元素標籤」,一個空元素標籤就是一個「元素」。

所以例子裡的

<circle cx="500" cy="350" r="300" fill="red"></circle>

可以寫成

<circle cx="500" cy="350" r="300" fill="red"/>

而標籤裡的「xx="yy"」,其中「xx」是該元素的一個「屬性」,「yy」是他的值,每個屬性要麼不寫出來(不寫出來表示使用默認值),寫了必須有「=」跟一個值,值必須用引號擴起來,多個屬性之間用空格隔開。在 SVG 裡什么元素有什麼屬性,屬性值格式都是規定好的,在這個例子裡我們只需要關注幾個簡單的就好。

回到動畫問題,我們需要做的就是把動畫元素作為 <circle> 元素的內容插入

<circle cx="100" cy="550" r="50" fill="#00BFFF">
  <animate attributeName="opacity" values="1;0" begin="0s" dur="1s"  repeatCount="indefinite"/>
</circle>

這樣就是讓這個圓做不透明度從 1 到 0 漸隱消失的動畫了。

這個例子裡為了讓效果明顯我將動畫元素裡的「repeatCount」屬性設為「"indefinite"」即讓它每次播放完再從頭播放,有時候會希望它只播放一遍,這時如果我們把「repeatCount」屬性設為「"1"」,會發現雖然動畫只播放一次了,卻沒有保持最後一刻的樣子,而是跳到了動畫播放前的狀態。此時我們需要再設置一個屬性「fill」令「fill="freeze"」,即:

<animate attributeName="opacity" values="1;0" begin="0s" dur="1s"  repeatCount="1" fill="freeze"/>

就能達到目的了。

另外動畫元素裡有個屬性「begin="0s"」表示動畫立即開始,如果是「begin="1s"」就是動畫延遲 1 秒再開始,用這個參數我們可以控制多個動畫的順序,比如讓幾個圓點依次消失:

透明度的動畫我們搞定了,接下來看看線條生長的動畫。同樣道理,我們把「attributeName」屬性設為「"d"」,「values」設為初始和結束時的路徑就好。

<animate attributeName="d" values="M100,550 L100,550;M100,550 L500,350" begin="0s" dur="1s" repeatCount="1" fill="freeze"/>

然後插入對應的 <path> 元素中就好。

多說一句,對於直線我們可以這麼寫,如果路徑是一條折線或者曲線就沒那麼簡單了,限於篇幅這裡不展開,感興趣可以看看文末的連結。現在我們綜合一下以上提到的知識,做一個「點閃爍出現 -> 線條生長 -> 另外一個點出現」的動畫:

<svg width="1000" height="1000" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <circle cx="100" cy="550" r="50" fill="#00BFFF" opacity="0">
        <animate attributeName="opacity" values="0;1;0;1;0;1;0;1" begin="0s" dur="0.5s" repeatCount="1" fill="freeze"/>
    </circle>
    <path stroke="#00BFFF" stroke-width="5" d="M100,550 L100,550">
        <animate attributeName="d" values="M100,550 L100,550;M100,550 L500,350" begin="0.5s" dur="0.5s" repeatCount="1" fill="freeze"/>
    </path>
    <circle cx="500" cy="350" r="50" fill="#00BFFF" opacity="0">
        <animate attributeName="opacity" values="0;1;0;1;0;1;0;1" begin="1s" dur="0.5s" repeatCount="1" fill="freeze"/>
    </circle>
</svg>

注意我將每個「需要做動畫的元素」裡的「需要做動畫的屬性」的值都設置為動畫開始前的狀態,比如<circle>元素都加上了「opacity="0"」,這樣就能保證動畫開始前整個畫面是空白的。

好了,點和線的動畫都搞定,我們就可以讓人臉上的特徵點動起來了。動畫的原理都很基礎,並不複雜,需要的是一點點耐心,和不斷的刷新測試,估計時間和節奏,仔細打磨。

這樣針對一張照片的動畫就基本完工了,但是每個人上傳的照片是不一樣的,怎麼保證動畫能對上位置呢?所以最終我做的是一個「SVG 動畫生成器」,通過獲取你上傳的照片所返回的特徵點位置數據,再生成位置匹配的 SVG 動畫代碼,嵌入到 H5 中。

我做了個簡陋的網站調用它,感興趣的可以掃下圖的碼或者複製連結到瀏覽器體驗一下。

http://bigxixi.com/svgdemo/genSVG.html

另外,首頁的「點擊拍照」和文字跑馬燈動畫也是 SVG ,用到了更多有意思的 SVG 動畫技巧,限於篇幅這裡不再深入,有機會再單獨講講。


使用設計軟體製作 SVG 動畫


前面說的都是直接用「代碼」製作動畫,但是對於我們設計師來說更友好的方式還是用軟體設計好靜態視覺元素,再添加點「代碼」讓它動起來。不過要讀懂並修改這些導出的「代碼」也是得花一點功夫的哦。我們來看看「點擊拍照」和「文字跑馬燈」這倆例子:

先說說「跑馬燈」,我是用 Sketch 把字排起來的(為了保證各個端字體一致我將文本轉曲了),然後畫了個遮罩,遮掉藍字部分,再將整個畫板導出為 SVG 。

我導出的時候沒有隱藏遮罩圖層,因為隱藏了遮罩就沒了……不知道算不算 Sketch 的小 bug 。沒關係,我們可以直接調整 SVG 代碼。

首先有一個要注意的點,請看我們之前章節寫的「代碼」的 <svg> 標籤那一行:

<svg width="1000" height="1000" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg">

最後的「xmlns="http://www.w3.org/2000/svg"」看起來像是個「超連結」,實際上只是個「定義」,告訴瀏覽器這裡的「代碼」遵循 SVG 標準,否則瀏覽器會無法正確讀取 SVG。

另外順便提一下,這裡的「width」、「height」表示寬、高,「viewBox」指定的是「可視區域」,「"0 0 1000 1000"」,意思是可視區域為以左上角(坐標 [0,0])到右下角(坐標 [1000,1000])為對角線的矩形區域,我們現在的數值是和 SVG 圖像的寬高一致,如果可視區域小於圖像寬高,或者對角線划過的區域不吻合,多出的部分將會被切掉看不見。然後是「version」是指的 SVG 標準的版本,現在是 1.1 版。

回到上一張圖裡,由 Sketch 導出的 SVG 代碼中,<svg> 標籤中又多了個屬性xmlns:xlink = "http://www.w3.org/1999/xlink"」這個設置開啟了 引用 功能。

我們看看圖中的第 6、7、8 行:

<defs>
    <polygon id="path-1" points="99 839 0 839 0 146 99 146 83.5898438 104.871094 83.5898438 27.8964844 99 0 742 0 742 996 99 996 79.4570312 976.712891 79.4570312 887.115234"></polygon>
</defs>

 <defs> 標籤有點像 Sketch 的 Symbol,標籤下的子元素可以被重複引用,並且如果沒有被引用,是不會出現在畫面裡的(不過 SVG 還有個 <symbol> 標籤,比 <defs> 能做更多設置,但是這裡沒出現,就不深入介紹了)。

這個 <polygon> 就是我畫的那個不規則遮罩,注意標籤裡有個屬性「id="path-1"」,這個「id」的值在整個 SVG 裡是 唯一 的,就像我們的身份證一樣。

再往下看到 10、11、12 行

<mask id="mask-2" fill="white">
    <use xlink:href="#path-1"></use>
</mask>

<mask> 標籤下的就是遮罩元素了,屬性裡「id="mask-2"」指定了它自己的 id,而「fill="white"」則是由於之前 <defs> 裡的 <polygon> 只定義了路徑沒定義填充色所以在這裡設置,對於 mask 來說,白色是完全顯示所遮罩的內容,如果寫成「fill="black"」就是什麼都看不見了,如果換成別的顏色比如 red 就是半透明。如果是漸變,就能做出有透明度變化的遮罩,如果是一張照片……哈哈這裡不深入展開了,感興趣可以用搜尋引擎搜索 SVG mask 了解一下。

中間的 <use> 就是引用了之前的 <defs> 裡定義的 id 為「path-1」的圖形。注意寫法「xlink:href="# + 引用的元素的 id +"」。

不過光有這句還不夠哦,這裡只是 定義 了一個遮罩元素,遮哪裡還需要對應的代碼配合才行。

其實如果們不用引用的方式,刪掉整個 <defs> ,直接把 <polygon> 元素放在 <mask> 下也是 OK 的,還更直觀。不過既然 Sketch 是這麼導出的,我們就按它的思路走,順便了解一下 <use> 的用法也不錯。

<mask id="mask-2" fill="white">
    <polygon id="path-1" points="99 839 0 839 0 146 99 146 83.5898438 104.871094 83.5898438 27.8964844 99 0 742 0 742 996 99 996 79.4570312 976.712891 79.4570312 887.115234"></polygon>
</mask>

接下來看看第 13 行:

<use id="textmask" fill="#D8D8D8" xlink:href="#path-1"></use>

這個 id 「textmask」是不是有點眼熟?看上面的 Sketch 文件界面截圖,最下面的遮罩圖層名就是「textmask」。沒錯 Sketch 導出 SVG 的時候會把圖層名設置為對應元素的 id ,如果同名就在後面加個「-1」、「-2」等。另外我們可以看到在 Sketch 的圖層順序裡「textmask」是在最下方的,SVG 中卻最先出現了,順序是反過來的哦!

之前說過 Sketch 導出 SVG 的時候為了帶上遮罩我沒有隱藏遮罩圖層,現在既然找到它了,哼哼,當然是直接刪掉或者注釋掉了。所謂注釋,就是將這一行不做為代碼處理,在 SVG 裡就是在要注釋的行前後加上「<!-- 」和「 -->」

這樣我們的圖就完美了。

然而遮罩的問題才剛開始……前面只提到了遮罩的定義,現在來說說怎麼用。我們用文本編輯器裡的「搜索」功能直接搜圖層名,比如「正臉」,就能定位到該圖層 id 所在:

旁邊就是遮罩 mask 的用法:

<id="正臉" …… mask="url(# + 遮罩圖層的 id + )">

這樣這個圖層就被遮罩圖層遮住了,其他幾個圖層也是如此。不過這裡提醒一下,雖然 id 可以用中文,但是在實際應用中最好使用 英文+數字,且不要帶上空格,不然會有亂碼出錯的風險。

總結一下遮罩的用法:

創建或者設置 <mask> 元素

在需要引用的元素標籤裡加上 「mask="url(# + 遮罩圖層的 id + )"」

簡單分析了 Sketch 導出的代碼,接下來可以開始做動畫了!先說說動畫的設計思路,其實就是保持遮罩不動,文字圖層水平或者垂直位移,由於文字是重複的,只需位移到「重合點」,再循環就好了。

之前的章節提到了 <animate> 標籤,這次我們用個新的 —— <animateTransform> ,看名字就知道它是專注於「變換動畫」的標籤,可以為這些屬性做動畫:

位移(translate)

旋轉(rotate)

縮放(scale)

傾斜 (skewX、skewY)

其寫法是:

<animateTransform 
   attributeName="transform"
    type="translate"
    from="0 0"
    to="-132.96 0"
    begin="0s"
    dur="1s"
    repeatCount="indefinite"
/>

(為了解釋方便我將屬性豎著排列了,注意每個屬性之間有空格)

後邊的屬性基本和  <animate> 一樣,主要是前面的「attributeName = "transform"」和「type = "translate"」,這裡「type」屬性指定了變換類型,「translate」就是位移動畫,[0 0]、[-132.96 0] 是坐標 [x y],為什麼是「-132.96」?當然是設計稿裡量出來的啦,移動這麼多距離正好和移動前重合。

這裡再擴展一個小技巧。我們之前的做法是將 <animate> 插入到需要動畫的元素中間作為其子元素,如果動畫很多,動畫相關的代碼就會分散於很多地方難以修改。而前面提到了「引用」,其實動畫也是可以「引用」的,只不過是把動畫自己「引」到目標上。做法也很簡單,在動畫標籤裡插入「xlink:href="# + 引用的元素的 id +" 」

<animateTransform 
        xlink:href="#正臉" 
        attributeName="transform"
        type="translate"
        from="0 0"
        to="-132.96 0"
        begin="0s"
        dur="1s"
        repeatCount="indefinite"
/>

總結一下「xmlns:xlink」引用的用法:

<svg> 標籤中引入屬性「xmlns:xlink = "http://www.w3.org/1999/xlink"」

在需要引用的地方設置 「xlink:href="# + 引用的元素的 id +" 」

這樣我們就可以跳出標籤,把動畫集中在一個地方方便修改了。

OK 我們來預覽一下動畫:

好像哪裡不對?是的,我們期望的是 遮罩不動字在動,現在是遮罩和字一起動了!怎麼回事呢?仔細想想,我們的遮罩是和文字圖層在一個標籤裡的:

所以動畫其實沒毛病!找到病因,我們要做的就是對症下藥:把遮罩從每個文字元素裡去掉,然後把他們放進一個「組」裡,再對這個組做遮罩,而動畫的目標是阻裡的文字層,組是不動的,這樣就能達到目的了!

SVG 裡分組很簡單,用 <g></g>  標籤把他們括起來就行。

別忘了最後加上結束標籤 </g>

好,現在再看看動畫,完美!

對其他幾組字再如法炮製,我們的跑馬燈就完成了!

然後我們再看「點擊拍照」。這個動畫分兩部分:底下斑馬線的循環移動,和按鈕的按下及回彈。首先看看設計稿:

「斑馬線」就是用很多條黑線排列,然一起旋轉,最後用一個方形遮罩讓它只露出方塊內部的部分。我們用「文字跑馬燈」動畫的做法讓它循環位移動畫就好。

然後是按鈕的按下動畫,也很簡單,就是將「點擊拍照」四個字、白色方塊,三根黑線作為一個組,對這個組進行位移動畫,而「按下」的時候三根黑線會超出這個 SVG 的「可視區域」範圍而被裁切掉。

  <animateTransform 
          xlink:href="#djpz" 
          attributeType="XML"
          attributeName="transform"
          type="translate"
          values="0 0;5 5;0 0;0 0"
          keyTimes="0;0.02;0.2;1"
          begin="0s"
          dur="2s"
          repeatCount="indefinite"
  />

這裡還有個屬性「keyTimes」。默認情況下我們如果不設置「keyTimes」,「values」中的值變化到下一個值的時間是固定的:比如動畫總時長2秒,「values」 裡有四個值「"0 0;5 5;0 0;0 0"」,那麼「0 0」到「5 5」、「5 5」到「0 0」、「0 0」到「0 0」用時都是 2/4 = 0.5 秒(小技巧:此處設置一個 「0 0」到「0 0」 是為了製造一個時間間隔);現在指定了「keyTimes = "0;0.02;0.2;1"」,那麼每段所用時間就變為:

「0 0」到「5 5」用時 2 x (0.02 - 0) = 0.04 秒

「5 5」到「0 0」用時 2 x (0.2 - 0.02) = 0.36 秒

「0 0」到「0 0」用時 2 x (1 - 0.2) = 1.6 秒

這樣就完成了「快速按下,再慢慢彈起,然後間隔一段時間,再重複按下」的動畫。

這兩個動畫的 SVG 文件和 Sketch 源文件可以複製下面的連結到瀏覽器下載 

☟☟☟

http://bigxixi.com/svgdemo/svgs2.zip

最後再聊聊首頁那個大衛石膏模型的動畫:

這個就不是 SVG 動畫了,是我用 AE 製作後,通過自己寫的 AE 腳本「CSS Sprite Exporter 」導出的 CSS 精靈圖動畫。關於這個可以看看我的另一篇文章,我覺得在 H5 項目裡還是挺實用的:

https://zhuanlan.zhihu.com/p/34731896



結束語

SVG 非常博大精深,可以說是 web 端 2D 動畫利器,作為設計師,可能會因為對「代碼」有恐懼心裡而不敢碰,其實沒有那麼難,多看資料,多多嘗試,多多思考,它會成為你一個從更多維度展現設計想法的絕妙途徑哦。

本文寫作過程中參考了以下文章和資料:

https://www.w3.org/TR/SVG11/

https://www.zhangxinxu.com/wordpress/?s=svg

http://www.oxxostudio.tw/articles/201409/svg-21-smil-animation.html


 撰文 ✎ 西西 

圖片 ✎ pexels.com、自製

未 經 允 許 請 勿 轉 載 到 其 他 公 眾 號

在 首 頁 輸 入 關 鍵 詞 轉 載 獲 得 授 權

···········································

相關焦點

  • SVG 線條動畫入門
    」二字查看說明通常我們說的 Web 動畫,包含了三大類。CSS3 動畫javascript 動畫(canvas)html 動畫(SVG)個人認為 3 種動畫各有優劣,實際應用中根據掌握情況作出取捨,本文討論的是我認為 SVG 中在實際項目中非常有應用價值 SVG 線條動畫。舉個慄子SVG 線條動畫,在一些特定的場合下可以解決使用 CSS 無法完成的動畫。
  • SVG動畫、CSS3動畫常用知識點全解析
    begin & dur & endbegin定義動畫開始時間;dur定義動畫所需時間;end定義動畫終止時間。時間單位h:小時;min:分鐘;s:秒;ms:毫秒。默認時間單位為sfill當fill="freeze"時,動畫終止時,發生變化的元素屬性值停留在動畫終止時的狀態;當fill="remove"時,動畫終止時,發生變化的元素屬性值回復到動畫起始時的狀態。
  • 【Web動畫】SVG 線條動畫
    通常我們說的 Web 動畫,包含了三大類。個人認為 3 種動畫各有優劣,實際應用中根據掌握情況作出取捨,本文討論的是我認為 SVG 中在實際項目中非常有應用價值 SVG 線條動畫。"5 5, 575 5, 575 200, 5 200" class="g-rect-path"/>    <polyline points="5 5, 575 5, 575 200, 5 200" class="g-rect-fill"/></svg>SVG 為何可縮放矢量圖形,即SVG
  • 一篇文章帶你了解SVG 動畫元素
    二、動畫選項概述這些SVG動畫元素中的每一個都設置或設置SVG形狀的不同方面的動畫。這些動畫元素將在本文的其餘部分中進行說明。1. set該set元素是SVG動畫元素中最簡單的元素。在經過特定時間間隔後,它只是將屬性設置為特定值。
  • Svg和CSS的結合--打勾動畫
    我們常常會在一些APP和網頁上看到這樣的動畫--當我們點擊某個按鈕時會看到頁面彈出或者顯示出一個提交成功等提示動畫。
  • svg 動畫介紹(一)
    今天講svg的動畫屬性 animate、animateTransform、animateMotion(第一節)SVG 動畫元素
  • SVG 實現動態模糊動畫效果
    在線演示(http://www.html5tricks.com/demo/html5-svg-motion-blur-effect/index.html)源碼下載(http://www.html5tricks.com/html5-svg-motion-blur-effect.html)動態模糊是靜止圖像或一系列圖像(如電影或動畫)中快速移動物體的明顯圖像拖尾
  • 線條之美,玩轉SVG線條動畫
    canvas動畫;利用canvas提供的API,然後利用清除-渲染這樣一幀一幀的做出動畫效果。svg動畫;同樣svg也提供了不少的API來實現動畫效果,並且兼容性也不差,本文主要講解一下如何製作svg線條動畫。先來看幾個效果:
  • 【Web動畫】SVG 實現複雜線條動畫
    在上一篇文章中,我們初步實現了一些利用基本圖形就能完成的線條動畫:【Web動畫】SVG 線條動畫入門[1]當然,事物都是朝著熵增焓減的方向發展的,複雜線條也肯定比有序線條要多。好,到了 PS 中的最後一步,點擊文件選項,導出路逕到 illustrator ,看圖,照著操作就好:
  • 使用 SVG 製作加載動畫
    這些都可以通過 CSS3 動畫來實現,剩下的我們需要對這些動畫進行拆分,先分別實現它們。最後將他們組合,通過一定的時間配合實現完整的效果。在這裡我將該動效最終拆分成了以下幾個部分:每一個單獨的動畫效果我們都需要對其進行處理,所以我們需要對導出的 SVG 進行元素的整理,將我們需要進行操作的元素進行分組標記。
  • 十分鐘教你用 svg 做出精美的動畫!
    前言經常在Codepen上看到大俠們用 SVG 畫出不可思議的動畫,我一直很好奇他們是怎麼運作的,總覺得這需要對 SVG 有足夠透徹的了解,並且自己畫出那些 SVG 圖案,才有辦法讓他動起來。但其實不然,今天教大家一個簡單的小技巧,讓你快速實現一個 svg 動畫!
  • 十分鐘教你用svg做出精美的動畫!
    前言經常在Codepen上看到大俠們用SVG畫出不可思議的動畫,我一直很好奇他們是怎麼運作的,總覺得這需要對SVG有足夠透徹的了解,並且自己畫出那些SVG圖案,才有辦法讓他動起來。但其實不然,今天教大家一個簡單的小技巧,讓你快速實現一個svg動畫!
  • 「數字虛擬人」堪比真人,「原力動畫」首次公開硬核科技
    在中國,36氪發現了一股在國內做「超寫實人物動畫」的力量,原力動畫。 和影視科技教父詹姆斯·卡梅隆監製的《阿麗塔》不同,「阿麗塔」使用了動作捕捉、表情捕捉和 CG 等技術,她的表情動作基於一個真實的人類演員;而原力持續開發的系統,是要跳過人類演員,讓計算機直接生成無限逼近人類、難辨真偽的虛擬演員。
  • 這個日本「黑科技女團」,又出了個讓人跪著看完的視頻!
    看完後網友們紛紛表示,「太震撼了!」「跪著看完」「還有那個團體如此黑科技?」不少廣告行業從業者的朋友看到之後甚至表示哀不自勝。如果你還沒看明白,請往下看!本次與 Perfume 與 NTT docomo 的合作名為「FUTURE-EXPERIMENT VOL.01 距離をなくせ。」即「體驗未來 VOL.01 -消除距離」。
  • 創投日報 | 「長揚科技」獲1.5億元C輪融資,「芯來科技」獲小米...
    創投日報收錄了今天「36氪創投頻道」報導的融資新聞,以及我們正在關注的各個領域早期創業項目,enjoy~ 科技 融資披露 36氪獲悉,RISC-V處理器內核IP和生態平臺公司企業——「芯來科技」宣布完成新一輪戰略融資,由小米長江產業基金領投,老股東藍馳創投和新微資本繼續追投。
  • 精確解決「求問這是什麼動畫,在線等」這個問題
    本文來自 @荔枝,幫你解決在網絡上看到圖片就問:「求問這是什麼動畫,在線等」的問題!
  • 互動動畫「石膏島」,探索互動影遊的「混血商業模式」
    針對前者,「陣風數字」CEO李京華告訴36氪,「石膏島」將會將交互選項與動畫中的其他元素進行串聯,比如不同玩家在戰鬥過程中使用魔法會消耗自己的記憶,而不同的記憶消耗量則會影響互動選項的數量和內容,達成千人千面的定製化互動體驗,不僅有助於減少觀眾對於重複選擇的疲倦感,還使交互動畫本身更具真實與挑戰性。
  • SVG排版公眾號圖文「實時計算日期差」模板代碼
    模板效果模板代碼svg代碼<svg data-author="懂點君" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink
  • Google零門檻黑科技,讓你跑到電影裡面看電影|挖App
    今天介紹的就是一款由 Google 出品的黑科技應用,它會將你的手機觀影體驗提升到的一個「看完第一眼就忍不住向身邊的人瘋狂安利」的水平……「Google Spotlight Stories」,一款出自 Google 團隊的視頻應用,運用的技術正是 Google 早已開始大力推廣的新型手機電影技術。
  • 運用超人、蝙蝠俠「顏色穿搭術」變型男
    其中各個角色的服裝都相當具有代表性,如蝙蝠俠的陰沉黑色、閃電俠的活潑紅色等,想必會成為今年聖誕變裝的最佳選擇,快來學學怎麼運用色彩搭配,穿得像超級英雄吧!#蝙蝠俠顏色指南:全黑DC最強英雄「超人」回歸,在《蝙蝠俠對超人:正義曙光》結尾犧牲的超人,先前外傳他將會換上黑色超人裝復活,究竟結果如何小編就不劇透了,這邊還是以超人深植人心的形象「藍色緊身衣+紅色小褲褲」作穿搭範例。