UI设计师福利——做一枚与众不同的loading动图

_SVG动画本质上是动图,我们并不能把它当做实现真正动画的工具,它比gif动图的优势在于小的体量,可交互,可矢量放大,方便修改色值,但它的劣势也很明显,渲染需要耗内存(所以能用基本的移动旋转等等实现就不要用路径变形),而且移动端应用需要第三方框架,即使web应用还要考虑到浏览器的支持(千刀万剐的ie),UI设计师也不是专业的动画设计师,所以关于SVG动画的应用,更多的是在一些微交互的细节上,比如现在要说的loading动图,就是其中一个应用场景。
关于加载时的动图,最常见的菊花已经被用滥了,在最开始接触SVG的时候,为了练手,做过一堆,如下:

各种样式的loading动图

这些都是最基本的样式,即使眼花缭乱,但实现起来都简单无比,无非就是旋转+宽高变化+位移。当你有充裕的时间,可以考虑多花费一点精力来打造一枚独一无二的loading图标。融入一点品牌或产品的调性,在小细节处体现一下设计感。下面由浅入深,步步拆解,看一枚特别的loading动图的做法。(老规矩,会附上可以复用的代码,方便UI设计师拿去用)

基本效果

先看一下下面这个动图

圆环长度变化

这里面是两个动画属性叠加,一个是旋转,一个是圆周的长度由0增加到全部周长。CSS样式部分代码如下:

@keyframes animate {
0%{stroke-dashoffset:943;transform:rotate(0)}
100%{stroke-dashoffset:0;transform:rotate(360deg)}
}
#load{
animation:animate 2s  ease infinite;
transform-origin:center center;/*定义旋转的原点*/
stroke-dasharray:943;/*计算得到的圆周周长*/
stroke-width:20px;/*圆形的描边各种属性值*/
stroke:#8879aa;
stroke-linecap: round;
fill:none
}

描边长度逐渐增加用虚线偏移位置stroke-dashoffset配合虚线样式stroke-dasharray来实现是最合适不过,第一次接触描边动画可以参考我的这篇文章 UI福利,svg描边动画效果,零代码基础手把手教你完成 http://www.jianshu.com/p/a3d66a920245
这里面注意一下圆形周长的计算,其他就是套用。
旋转动画就比较乏善可陈了,最基本的用法。
然后用<circle>标签引用load属性(id="load")就可以实现这种长短变化+旋转的动效。
了解了这些,就可以看一枚与众不同的loading图标了

创意来源

创意来源

这是我在dribbble看到的一枚图标,当时就震惊了,原来除了那些千篇一律的加载图标,这货居然还可以做成这样!也深深的感慨到自己的差距,空有一些技法,但创意渣到空白。
不过既然看到了,那就想个方法来实现这种效果。先模仿再创新嘛。
先说这个cat的选取,很恰到好处,本来喵星人的身体就有这种拉伸的属性,你能想象如果换成一头身子被拉伸的大象嘛?当然了,这也导致我在模仿这枚图标的时候思索了好久,不过还是选了我喜欢的一头小狮子。效果差强人意。

底图

我的底图就是上面这只可爱的小狮子,我想象中的效果是狮子被分割成3部分,头(A)+身体(B)+尾巴(C)。旋转的过程就是身体拉伸的过程。思路如下图所示。

动画思路

改造底图

为了保证狮子身体拉伸时与头部和尾巴实现无缝对接,要对小狮子进行一些小改造,把圆弧的一段嵌入到身体中。
首先在AI里做一个圆形,描边的粗度就是可伸缩的小狮子的身体,调整小狮子的大小和位置。

确定好各个元素的位置

剩下的工作对于UI来说还是比较简单的,相同位置复制一个圆形,只取其中一小段弧形,进行扩展,由路径变成形状,调节狮子原来的身体,使圆弧能够完全与头部和尾巴契合。

调整

调整之后,原来小狮子的身体就由一段圆弧代替了,此时,再对小狮子的身体进行切割,前半部分与头部组合,后半部分与尾巴组合。
至此,对于小狮子的改造全部完成。

不同运动速率的头部和尾巴

根据前面的分析,我们的头部要走的快一点,尾巴要走的慢一点,这样才能实现把身体拉伸的效果。
这里有不同的方法来实现,我使用的方法是控制关键帧。代码如下:

@keyframes right{
0%{transform:rotate(0); } /*定义头部旋转动画*/
75%{transform:rotate(360deg);}/*头部完成动画时间1.5s(2*0.75s)*/
100%{transform:rotate(360deg); }
}
@keyframes left{
0%{transform:rotate(0); } /*定义尾巴旋转动画*/
100%{transform:rotate(360deg);}
}
#moveRight{animation:right 2s ease  infinite;transform-origin:300px 300px}/*旋转中心点为圆形原点*/
#moveLeft{animation:left 2s ease infinite;transform-origin:300px 300px}

通过增加时间节点75%的关键帧,使头部旋转的动画时间缩短为定义时间2s的75%,即1.5s完成旋转360度,而尾巴则是2s完成旋转360度,从而实现头部与尾巴的速度差,也就意味着头部比尾巴提前0.5s到达终点。

可伸缩的身体部分

关于可伸缩的身体部分是这个动效的重点,因为身体的伸缩要与头部和尾巴保持一致才能组成一个无懈可击的整体。
还记得最开始的那个长度从零增加到圆周长的紫色圆环吧,我们利用的是stroke-dashoffset配合stroke-dasharray来完成的。这里仍然利用这个原理来实现弹性伸缩的身体。思路如下:


首先我把一圈的身体做为底图,然后利用蒙版(不了解SVG蒙版动画的小伙伴先看一下我的关于SVG蒙版动画的文章)来实现。蒙版上分别画两条路径,一条是白色,为了露出身体底图部分,运动速率与头部保持一致,同时,一条为黑色,运动速率落后于白色,为了消除掉多余的身体部分,运动速率与尾巴保持一致。形象一点来说,就是白色描边蒙版在前面跑,后面黑色描边蒙版在追赶,直到完成一个周期的运动。
对应的CSS部分如下:

/*定义白色描边动画,速度与头部旋转动画保持一致*/
@keyframes middle{
0%{stroke-dashoffset:942.48}
75%{stroke-dashoffset:0}
100%{stroke-dashoffset:0}
}
/*定义黑色描边动画,速度与尾巴旋转动画保持一致*/
@keyframes middle2{
0%{stroke-dashoffset:942.48; stroke:#000000}
100%{stroke-dashoffset:0; stroke:#000000}
}
#moveMiddle{stroke-dasharray:942.48;animation:middle  2s ease infinite;}
#moveMiddle2{stroke-dasharray:942.48;animation:middle2 2s ease infinite;}
#base{fill:#f8b602;mask:url(#shade)}/*定义底图样式,并调用蒙版*/

代码部分如下:

<mask id="shade">
<path id="moveMiddle" fill="none" stroke="#ffffff" stroke-width="40" stroke-miterlimit="10" d=""/> <!--用以逐渐显示底图的白色蒙版-->
<path id="moveMiddle2" fill="none" stroke="#ffffff" stroke-width="40" stroke-miterlimit="10" d=""/> <!--用以消除的黑色蒙版-->
</mask><!--以上蒙版的两个d值相同,均为圆形对应的路径-->
<path id="base" d=""/> <!--d值为组成身体底图的路径-->
<g id="moveLeft" >此处若干组成头部的代码……</g>
<g id="moveRight" >此处若干组成尾巴的代码……</g>    

这里需要注意,我的动态描边蒙版的路径(圆形)被我从狮子身体位置断开,以便控制描边动画的起点/终点。加上个好看的底色看一下效果:

loading lion

哟,看这弹性无比的身体。看这无缝拼接,完美啊。
打住,既然做都做了,这里我们要继续深入研究一下各个参数的修改都会对动效产生什么影响。

参数调整对动效的影响

这里面除了小狮子转圈的速度,那个我们从代码里能一眼看出来,一圈是2s,我们来看一下我定义的时间轴的75%的关键帧,如果修改成其他值,会对动效产生什么影响。
其他不变,我只把关键帧的时间点改成50%看一下(记得白色描边蒙版动画与头部是捆绑在一起的,要改一起改,否则可怜的小狮子就会出现身体断开或者身体跑到头部前面等等诡异的现象)效果。

头部完成一圈旋转动画关键帧定义在50%

哎呀呀,小狮子你肿么了,身体被拉长好多……是的,当我们能理解这个关键帧的含义时,就会知道,当头部和白色蒙版的旋转一周的关键帧定义到50%时,意味着头部在1s即50%就完成了一圈的旋转动画,剩下的50%在等尾巴跟上来,也就是说狮子的身体部分最长可被拉长到圆周的1/2。
那同样当我把时间轴的关键帧定义为90%时,效果是下面这样的:

头部完成一圈旋转动画关键帧定义在90%

小狮子的身体被拉长的很轻微。所以这里代码如果要复用的时候,各位UI设计师可以根据实际情况自己去调整关键帧的位置。

一个周期旋转N圈

回头再看看带给我们灵感的那只喵星人,然后对比一下我们的小狮子,最大的区别在哪里,嗯,小狮子每个动画周期只旋转了一周,而喵星人是两周??
如果不考虑身体部分,甭说两周,就是三周,四周,三千六百度空翻都没有问题,因为我们的选择动画rotate那里可以填角度。
比如我把旋转动画改成下面这样

@keyframes right{
0%{transform:rotate(0); }
75%{transform:rotate(720deg);} /*720度为旋转2圈*/
100%{transform:rotate(720deg); }
}
@keyframes left{
0%{transform:rotate(0); }
100%{transform:rotate(720deg);}
}

为了转起来不头晕,完成一个动画周期的时间我同样加倍了一下,改成了4s。

#moveRight{animation:right 4s ease  infinite;transform-origin:300px 300px}
#moveLeft{animation:left 4s ease infinite;transform-origin:300px 300px}

看一下头部和尾巴是不是一个周期旋转2圈

一个动画周期旋转2圈的小狮子

那比较难实现的就是身体部分了,我们一直是让描边动态蒙版来完成的,而描边路径,除了做了一下断开自定义起点,并没有做其他的操作,那怎么让描边的路径也能任意加倍呢?那个,暂时放弃。下午做了几种尝试,均已失败告终,给圆形路径加倍不是问题,最主要的问题就是黑色描边一圈后完全遮盖住了下面的描边效果。等有解决方法再更新。有空会尝试用蒙版套蒙版的方法。

补充,方才灵光一现,问题迎刃而解,这感觉,仿佛被打通任督二脉,废话不说了,直接说我的解决方法。
在做扇形扫描效果时,我用了白色蒙版围绕底图的圆圈中心点旋转方法,这里解决方法类似,不过比那个还要简单。

实现原理

我蒙版的建立是个“奥利奥”,上下黑色夹白色夹心。白色蒙版旋转时黑色蒙版一直再追,设定几圈就几圈后追上。
看一下效果是否达到预期
双层蒙版实现的弹性身体部分

哇,成功,完全不受描边动画的那种限制。而且这个方法最合理的地方还在于可以和头部及尾巴动画共用动画设定。完全实现了各种托马斯旋转。
在我的案例中,因为小狮子身体断开的部分并不是严格的圆形顶部,而是逆时针偏差了10度左右。这个AI就帮我们处理了,当调整过角度之后,导出的矩形<rect>标签会有一个变形属性transform="matrix()"。当然了,这里我用的矩形,但实际使用过程,可以用半圆形等等其他形状。
好了现在与狮子的头部和尾巴合体!

旋转2圈

既然这个方法快又好,那么就放上基础代码并简单注释

<svg>
<style>
/*定义头部以及白色蒙版的旋转动画 旋转度数可以任意定义*/
@keyframes right{
0%{transform:rotate(0); }
85%{transform:rotate(720deg);}
100%{transform:rotate(720deg); }
}
/*定义尾巴以及黑色蒙版的旋转动画*/
@keyframes left{
0%{transform:rotate(0); }
100%{transform:rotate(720deg);}
}
/*由于两个元素调用相同动画,所以定义成类*/
.moveRight{animation:right 4s ease  infinite;transform-origin:300px 300px}
.moveLeft{animation:left 4s ease infinite;transform-origin:300px 300px}
/*定义底图*/
#base{fill:#f8b602;mask:url(#shade)}
</style>
<rect x="0" y="0" width="600" height="600" fill="#e5dcc5"/><!--图形底色-->
<mask id="shade">
<rect x="0" y="0" width="600" height="600" fill="#000000"/><!--“奥利奥”蒙版的最底层黑色部分-->
<rect  fill="#ffffff" width="300" height="600" class="moveRight"/><!--“奥利奥”蒙版的中间层白色部分-->
<rect  fill="#000000" width="300" height="600" class="moveLeft"/><!--“奥利奥”蒙版的最上层黑色部分-->
</mask>
<path id="base" d=""/>
<g class="moveLeft" ><!--以下为组成狮子头部的代码-->

</g>
<g class="moveRight"><!--以下为组成狮子尾巴的代码-->

</g>
</svg>

有了基础模板,修改起来就方便多了,比如我想实现转3圈的效果,直接把transform:rotate(720deg)改成transform:rotate(1080deg)就可以了。
不过圈数越多,身体被拉伸的越厉害,可以适当调整一下头部的结束的关键帧,使速度变慢,比如我改成92%后,就得到了下面这种效果:

选择3圈

各种随意发挥,就酱,完美收工。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容