关于svg:使用-SVG-制作加载动画

7次阅读

共计 4500 个字符,预计需要花费 12 分钟才能阅读完成。

最近咱们设计师反馈,他想要做如下的一个加载动画。然而要么成果好的导出的 GIF 体积特地大,看了下有 8M 多了,要么体积小的 GIF 成果又特地不分明。而后我看了下成果,发现其实用 SVG 动画来实现应该比较简单,于是就和设计师要了一下原始的稿子导出成 SVG 后处理了下。

因为 SF 不反对插入视频,大家能够拜访腾讯视频地址 https://v.qq.com/txp/iframe/p… 查看设计师预期的动效视频。

将 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 动画实际》。

动画拆分剖析

通过观察发现该动画次要用到了平移、旋转、透明度,宽度和色彩等属性变动等动画成果。这些都能够通过 CSS3 动画来实现,剩下的咱们须要对这些动画进行拆分,先别离实现它们。最初将他们组合,通过肯定的工夫配合实现残缺的成果。

在这里我将该动效最终拆分成了以下几个局部:

  • 外圈的波纹成果

    • 外圈 1 的波纹成果
    • 外圈 2 的波纹成果
    • 外圈 3 的波纹成果
  • 主体的舒展静止

    • 主体绿色局部的平移舒展

      • 主体绿色局部上的平移舒展
      • 主体绿色局部下的平移舒展
    • 主体红色圆球的渐隐成果
    • 主体蓝色局部的平移舒展
    • 主体红色横条的渐隐成果
    • 主体局部的自转
  • 蓝球的公转成果

每一个独自的动画成果咱们都须要对其进行解决,所以咱们须要对导出的 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/…

主体的舒展静止

这块是整个外面比较复杂的一部分了,不过通过拆分,咱们发现实现起来也比较简单,先实现外部元素的平移,而后再补充上整体的自转成果即可。平移这块没有什么多说的,惟一麻烦的就是通过起始帧和完结帧的地位计算出须要挪动的间隔而已。如图最终白线标记的地位就是咱们须要的平移地位啦。

#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/…

蓝球的公转成果

动画拆分里的最初一步就是蓝球的公转成果了。从上文咱们晓得,旋转咱们是能够设置旋转圆心的。自转是围绕本人转的,所以旋转圆心是本人的核心,公转则是围绕太阳转的,所以旋转圆心是太阳的圆心,对应到咱们的动效里其实就是整个画布的核心。

在这里我还应用了 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/e…

后记

最初将下面的代码拼凑起来就能够实现文章结尾的动画成果了,是不是还挺简略的。另外在 SVG 标签中也反对内嵌 <style><script> 标签,所以咱们能够间接将款式内嵌在 SVG 文件中,这样咱们就能够和援用 GIF 一样间接应用 <img> 或者背景图片的模式应用 SVG 而不须要其余累赘,在一些不反对内嵌款式的 Markdown 网站比方 Github 中成果奇佳哦!

正文完
 0