最近咱们设计师反馈,他想要作以下的一个加载动画。可是要么效果好的导出的 GIF 体积特别大,看了下有 8M 多了,要么体积小的 GIF 效果又特别不清楚。而后我看了下效果,发现其实用 SVG 动画来实现应该比较简单,因而就和设计师要了一下原始的稿子导出成 SVG 后处理了下。css
因为 SF 不支持插入视频,你们能够访问腾讯视频地址 https://v.qq.com/txp/iframe/p... 查看设计师预期的动效视频。html
将 AE 动效稿子转成 SVG 动画的话 Airbnb 有出过一款 Lottie 的工具。经过它的 AE 插件 Bodymovin 可以以 JSON 的形式导出动画信息和素材。而后在网页上使用 bodymovin.js
动画播放库载入该 JSON 素材便可完成动效的转换。具体的使用教程能够参考 Youtube 视频《How to export an animation with Bodymovin》。web
使用 Bodymovin 是真的很是方便,不过介于设计师须要的效果比较简单,为了这个效果而每次去加载一个几十KB的基础库和JSON文件实在是没有必要。因此我这里就基于 SVG + CSS 动画来实现了下,最终的效果以下。最终体积也就 6KB,gzip 后会更小。
下面就来跟着我一块一步步的实现它吧!这里我不会特别详细的描述每一步的基本原理,若是你们想了解 SVG 动画的基础知识的话能够先看看我以前写的文章《SVG 动画实践》。ide
经过观察发现该动画主要用到了平移、旋转、透明度,宽度和颜色等属性变化等动画效果。这些均可以经过 CSS3 动画来实现,剩下的咱们须要对这些动画进行拆分,先分别实现它们。最后将他们组合,经过必定的时间配合实现完整的效果。svg
在这里我将该动效最终拆分红了如下几个部分:工具
外圈的波纹效果post
主体的伸展运动优化
主体绿色部分的平移伸展动画
每个单独的动画效果咱们都须要对其进行处理,因此咱们须要对导出的 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 中效果奇佳哦!