使用 SVG 製作加載動畫

2021-03-01 奇舞精選


最近我們設計師反饋,他想要做如下的一個加載動畫。但是要麼效果好的導出的 GIF 體積特別大,看了下有 8M 多了,要麼體積小的 GIF 效果又特別不清楚。然後我看了下效果,發現其實用 SVG 動畫來實現應該比較簡單,於是就和設計師要了一下原始的稿子導出成 SVG 後處理了下。

將 AE 動效稿子轉成 SVG 動畫的話 Airbnb 有出過一款 Lottie 的工具。通過它的 AE 插件 Bodymovin 能夠以 JSON 的形式導出動畫信息和素材。然後在網頁上使用 bodymovin.js 動畫播放庫載入該 JSON 素材即可完成動效的轉換。具體的使用教程可以參考 Youtube 視頻《How to export an animation with Bodymovin》。

使用 Bodymovin 是真的非常方便,不過介於設計師需要的效果比較簡單,為了這個效果而每次去加載一個幾十KB的基礎庫和JSON文件實在是沒有必要。所以我這裡就基於 SVG + CSS 動畫來實現了下,最終的效果如下。最終體積也就 6KB,gzip 後會更小。

下面就來跟著我一塊一步步的實現它吧!這裡我不會特別詳細的描述每一步的基本原理,如果大家想了解 SVG 動畫的基礎知識的話可以先看看我之前寫的文章《SVG 動畫實踐1》。

動畫拆分分析

通過觀察發現該動畫主要用到了平移、旋轉、透明度,寬度和顏色等屬性變化等動畫效果。這些都可以通過 CSS3 動畫來實現,剩下的我們需要對這些動畫進行拆分,先分別實現它們。最後將他們組合,通過一定的時間配合實現完整的效果。

在這裡我將該動效最終拆分成了以下幾個部分:

每一個單獨的動畫效果我們都需要對其進行處理,所以我們需要對導出的 SVG 進行元素的整理,將我們需要進行操作的元素進行分組標記。由於 Sketch 導出的 SVG 文件會帶有比較多的冗餘元素,所以我一般會在手工處理 SVG 之前在走一遍 svgo 這類工具對內容進行優化。這裡推薦張鑫旭老師寫的 SVG 在線壓縮合併工具,直接粘貼 SVG 代碼過去即可,非常簡單。下面是 SVG 整體結構的示意代碼。

<svg width="552px" height="552px" viewBox="0 0 552 552" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">

  <!--外圈-->

  <g id="track-list">

    <!--外圈1-->

    <circle id="track-circle-1" />

    <!--外圈2-->

    <circle id="track-circle-2" />

    <!--外圈3-->

    <circle id="track-circle-3" />

  </g>

  <!--中間主體-->

  <g id="main">

    <!--主體綠色部分下-->

    <g id="bottom-triangel">

      <path d="..." />

    </g>

    <!--主體綠色部分上-->

    <g id="top-triangel">

      <path id="shadow" d="..." />

    <path d="..." />

    <!--主體白色圓球-->

      <circle id="white-ball" />

    </g>

    <!--主體藍色部分-->

    <g id="right-triangel">

      <path d="..." />

      <!--主體白色橫條-->

      <rect id="white-line" />

    </g>

  </g>

  <!--外圈藍球-->

  <circle id="blue-ball" />

</svg>

可以看到我對 SVG 內的元素進行了重新的整理,將需要操作的元素都加上了 id 屬性,方便後續直接使用 CSS 選擇器選擇對象進行操作。另外所有需要一塊進行操作的元素也都使用 <g /> 分組標籤進行了包裹。

外圈的波紋效果

外圈的波紋效果本質上就是圓的半徑慢慢放大,效果裡還伴隨了圓的邊框變窄的一個過程。其中三個圓最內層的那個是不需要動的,只需要動後面兩個即可。從設計稿中拿到結束幀的狀態之後這個動畫做起來就比較容易了。

#track-circle-2 {

  animation-name: wave1;

  animation-timing-function: ease-in-out;

  animation-duration: 6s;

  animation-iteration-count: infinite;

}

#track-circle-3 {

  animation-name: wave2;

  animation-timing-function: ease-in-out;

  animation-duration: 6s;

  animation-iteration-count: infinite;

}

@keyframes wave1 {

  50% {

    stroke-width: 4;

    r: 219px;

  }

}

@keyframes wave2 {

  50% {

    stroke-width: 3;

    r: 274.5px;

  }

}

預覽地址: https://code.h5jun.com/xovew/edit?output

主體的伸展運動

這塊是整個裡面比較複雜的一部分了,不過通過拆分,我們發現實現起來也比較簡單,先實現內部元素的平移,然後再補充上整體的自轉效果即可。平移這塊沒有什麼多說的,唯一麻煩的就是通過起始幀和結束幀的位置計算出需要移動的距離而已。如圖最終白線標記的位置就是我們需要的平移位置啦。

#top-triangel { animation: topmove ease-in-out 2s infinite; }

#shadow { animation: shadowhide linear 2s infinite; }

#bottom-triangel { animation: bottommove ease-in-out 2s infinite; }

#right-triangel { animation-name: rightmove ease-in-out 2s infinite; }

@keyframes topmove {

  from, to { transform: translate(0, 0); }

  50% { transform: translate(-31px, -30px); }

}

@keyframes bottommove {

  from, to { transform: translate(0, 0); }

  50% { transform: translate(-31px, 30px); }

}

@keyframes rightmove {

  from, to { transform: translate(0); }

  50% { transform: translate(29px); }

}

@keyframes shadowhide {

  30%, 70% { opacity: 0; }

}

對了,別忘記我們剛才的動畫拆分裡還有白色圓球和白色橫條的漸隱效果。漸隱效果可以使用 opacity 透明度來實現,不過這裡除了漸隱之外還有一個大小的變化,可能使用呼吸效果來表述會更合適一點。圓的大小就是修改半徑,橫條的大小我們直接修改寬度就可以了。

#white-ball { animation: balltransparent ease-in-out 2s infinite; }

#white-line { animation: linetransparent ease-in-out 2s infinite; }

@keyframes balltransparent {

  50% {

    opacity: 0;

    transform: scale(0);

  }

}

@keyframes linetransparent {

  50% {

    opacity: 0;

    width: 0px;

  }

}

根據剛才的動畫拆分,主體部分我們就還剩下一個自轉沒有實現了。在做這一部分的時候需要注意兩點。第一,旋轉默認是基於 SVG 畫布的左上角進行旋轉的,自轉的話一般都是基於中心旋轉,所以一定要記得設置 transform-origin 為中心點。第二,Sketch 導出的 SVG 會存在大量的 translate() 平移屬性操作,有可能是最開始設計師畫的時候是在某個位置,後來覺得不合適進行了移動,在 SVG 裡就會以平移變換體現出來。這個時候如果我們直接使用 transform 進行變換的話實際上是會複寫掉它們原本的平移的,這樣就導致了之前設置的旋轉圓心不正確的問題。

所以這種情況下需要使用聯合變換,將之前的平移變換補充到 CSS 的變換中來就可以了,這也是為什麼代碼中會多出兩個 translate() 的原因。

#main {

  animation: mainrotate linear 6s infinite;

  transform-origin: center center;

}

@keyframes mainrotate {

  from {

    transform: translate(0, 0) rotateZ(0deg) translate(-72px, -42px);

  }

  to {

    transform: translate(0, 0) rotateZ(360deg) translate(-72px, -42px);

  }

}

下面就是最終的實現效果。怎麼樣,是不是感覺已經離勝利不遠了!

預覽地址: https://code.h5jun.com/dahag/edit?output

藍球的公轉效果

動畫拆分裡的最後一步就是藍球的公轉效果了。從上文我們知道,旋轉我們是可以設置旋轉圓心的。自轉是圍繞自己轉的,所以旋轉圓心是自己的中心,公轉則是圍繞太陽轉的,所以旋轉圓心是太陽的圓心,對應到我們的動效裡其實就是整個畫布的中心。

在這裡我還使用了 CSS 表達角度的另外一個單位 turn,它表示的是圈數,轉 360° 就表示 1turn。除了 turn 之外,CSS 角度還有 grad 梯度和 rad 弧度這兩個單位。grad 則是將一個圓劃分成了400等分,轉 360° 就表示 400grad。而 rad 弧度則和我們數學上的弧度表示基本一致,一個圓總共是 2πrad。

#blue-ball {

  animation: spin linear 6s infinite;

  transform-origin: center center;

}

@keyframes spin {

  from { transform: rotate(0turn); }

  to { transform: rotate(1turn); }

}

預覽地址: https://code.h5jun.com/kiqi/edit?output

後記

最後將上面的代碼拼湊起來就可以實現文章開頭的動畫效果了,是不是還挺簡單的。另外在 SVG 標籤中也支持內嵌 <style> 和 <script> 標籤,所以我們可以直接將樣式內嵌在 SVG 文件中,這樣我們就可以和引用 GIF 一樣直接使用 <img> 或者背景圖片的形式使用 SVG 而不需要其他負擔,在一些不支持內嵌樣式的 Markdown 網站比如 Github 中效果奇佳哦!

文內連結

https://75.team/post/svg-animation-in-action.html

關於奇舞周刊

《奇舞周刊》是360公司專業前端團隊「奇舞團」運營的前端技術社區。關注公眾號後,直接發送連結到後臺即可給我們投稿。

相關焦點

  • SVG - 動畫製作
    SVG - 動畫製作HTML5學堂:SVG - 動畫製作。
  • SVG動畫案例的學習
    處理蒙版你可能已經在圖6注意到了<Clip Group>圖層。本質上它們是在Illustrator中創建的剪切蒙版。當導出SVG時,它們會自動被重新定義為clipPaths,可以以相同的方式遮擋元素。
  • 使用SVG製作進度條
    今天我們來看看怎麼使用SVG來實現進度條的效果。使用SVG可以很容易的實現,也易於理解,最主要是使用SVG實現的進度條具有良好的跨瀏覽器,並且能根據瀏覽器屏幕尺寸很好的顯示。基礎在具體製作之前,有一些簡單的概念要了解一下,這是製作進度條的一些基礎。
  • 【Web動畫】SVG 線條動畫
    舉個慄子SVG 線條動畫,在一些特定的場合下可以解決使用 CSS 無法完成的動畫。尤其是在進度條方面,看看最近項目裡的一個小需求,一個這種形狀的進度條:把裡面的進度條單獨拿出來,也就是需要實現這樣一個效果:
  • SVG 線條動畫入門
    CSS3 動畫javascript 動畫(canvas)html 動畫(SVG)個人認為 3 種動畫各有優劣,實際應用中根據掌握情況作出取捨,本文討論的是我認為 SVG 中在實際項目中非常有應用價值 SVG 線條動畫。舉個慄子SVG 線條動畫,在一些特定的場合下可以解決使用 CSS 無法完成的動畫。
  • 【Web動畫】SVG 實現複雜線條動畫
    所以,很多時候,我們無法人工去畫出一些十分複雜動畫的線條,這個時候,就要藉助我們前端的好幫手 PS 和 AI:好了,假定我們現在要製作下圖 GIF 這樣的一個 loading 圖:可能你看到的是一片空白,別慌,使用選擇工具選一個矩形,就能選中路徑啦。
  • 10 個非常有用的 SVG 動畫的 JavaScript 庫
    此外,你甚至可以讓SVG動起來,通過使用一些javascript類庫。下面,我們分享一些javascript類庫,這些類庫會幫助我們將SVG動畫提高一個等級。 VivusVivus 是一個能動畫js類庫,它能夠給SVG圖像顯示出被畫出來的過程。Vivus是沒有其他類庫依賴的(比如jQuery)。
  • SVG 圖案動畫(Pattern)
    🖼️ SVG 圖案動畫(Pattern)想要在Web頁面中繪製背景圖案,我們首先可能想到的是使用 CSS,可能你也有所嘗試,比如簡單的漸變到複雜的網格、點陣等,SVG 中也有繪製背景圖案的解決方案。像這樣:chapter9-1原理在 Web 頁面開發中如果想使用 SVG 生成背景,實際上有兩種使用方法:SVG Pattern一個純 SVG Pattern 使用的過程大致如下:創建一個新的圖形,使用 SVG 中的 fill 屬性,填充圖案
  • 簡單 ionic 加載動畫
    在做項目的時候需要用到加載的動畫,因為用到了 ionic 這個框架,框架裡面的ionSpinner 提供了許多種旋轉加載的動畫圖標
  • 使用Anime.js製作火箭升空的動畫效果
    依照我web項目開發的經驗,既然這幾種動畫效果的實現方式都已經成為web標準,那麼肯定有很多人已經或者至少想過封裝出更加易用的工具庫或者是腳手架。繼續搜索🔍"web animation package", 然後找到了一個匹配度很高的JS庫:anime,使用anime可以為dom結構,css屬性,svg圖片,JS對象創建動畫效果,看了下文檔,簡單的動畫效果很容易實現。
  • SVG 實現動態模糊動畫效果
    如果好文章投稿,點擊 → 了解詳情今天我們將向大家展示如何製作SVG動態模糊效果,並將其應用於HTML元素的常規JS或CSS動畫。動態模糊是一種廣泛使用於動態影像和動畫的技術,它能使動作看起來更加平滑自然。
  • 使用 SVG 輸出 Octicon
    /GitHub.com 現在不再使用字體來輸出圖標了。為何使用 SVG?圖標字體渲染問題圖標字體從來只是一種 hack。我們之前使用一個自定義字體,並將圖標作為 Unicode 符號。這樣圖標字體就可以通過打包後的 CSS 來引入。只要簡單地在任意元素上添加一個 class,圖標就可以顯示出來。
  • SVG 圖標製作指南
    請儘量保持 SVG sprite 文件與源文件同步。當然如果你有 Grunt/Gulp 做自動構建打包時,你只需要維護一份圖標源文件(即icons 文件夾)。第三步:將圖標放到網頁中為了使用 SVG 圖標,我們得把它放到 HTML 中去,我們不能用 CSS 的 background 相關屬性,不能使用 ::before 等偽元素。
  • HTML+CSS+SVG實現加載動畫
    style="--i:4;"></span> <span style="--i:5;"></span> <span style="--i:6;"></span> <span style="--i:7;"></span> </div> <svg
  • SVG 變形動畫(Morphing)
    ⭐ SVG 變形動畫(Morphing)演示原理平滑的變形動畫真的算是 SVG 中的「獨門武器」了。其原理很容易想到。就是不同形狀之間能平滑轉換,SVG 中的形狀其實也是有不同坐標之間的線段繪製而成的。那麼在轉換形狀的時候,只是在移動線段的坐標。從而達到了形狀改變的效果,加之平滑的動畫展現。
  • CSS3 SVG實現可愛的動物哈士奇和狐狸動畫
    如有好文章投稿,請點擊 → 這裡了解詳情今天,我想向大家展示如何巧妙地使用HTML、CSS排序動畫和SVG濾鏡把生活中可能最可愛的東西之一——動物畫到網頁上。我們將探討繪製動物的兩種技術:一種使用純HTML和CSS,另一種使用內聯SVG背景圖像。此演示高度實驗性質——動畫SVG濾鏡目前僅在Chrome中可用。所涉及的動畫也很複雜,因此本教程將重點介紹創建這些動物以及栩栩如生的動作所涉及的不同技術。放飛你的創意,自行創作獨特和俏皮的動物動畫吧。話不多說,開始咯!
  • SVG 文字 hover 線條動畫
    效果如下:關鍵點使用了 stroke-dasharray 和 stroke-dashoffset 控制線條動畫。
  • Svg和CSS的結合--打勾動畫
    我們常常會在一些APP和網頁上看到這樣的動畫--當我們點擊某個按鈕時會看到頁面彈出或者顯示出一個提交成功等提示動畫。
  • 十分鐘教你用svg做出精美的動畫!
    尋找精美的svg圖案既然自己畫不出來,那我們就去找現成的庫,svg庫有很多,如Flaticon(https://www.flaticon.com/)、iconfont、Iconfinder或icons8等網站會提供很多免費的svg圖案。
  • 怎麼使用 SVG 作為一個圖像佔位符
    我對怎麼去讓 web 性能更優化和圖像加載的更快充滿了熱情。在這些感興趣的領域中的其中一項研究就是佔位符:當圖像還沒有被加載的時候應該去展示些什麼?在前些天,我偶然發現了使用 SVG 的一些加載技術,我將在這篇文章中談論它。