利用CSS3的animation step属性实现wifi动画(结尾有彩蛋)

4,306 阅读8分钟

之前攒的满满的SVG+CSS3做动画的技能一直未能放个大招,理由很简单,因为本身从事行业的性质,软件里不能出现劳什子动画这等花里胡哨的东西,哦,不不,叫隐喻行为引导的趣味化。用canvas实现了一个科技感满满的动态绘制背景的登录页面,因为渲染占了20M内存,20M啊筒子们,那就是将近1个G啊,然后,就没有然后了,谁让客户的机器还有1G内存的呢。至于唯一被使用的loading图标,no,no,no,前端只用默认的,懒得改。最近在做的一个软件有个刷卡的界面,就需要有一枚图标来表示开启“刷卡监听”状态,机会来了,终于有了实践的机会,什么?你说静态图片就可以?不不,动态表达的含义更明确,就这么愉快的决定了。

动画拆解
动画拆解

因为只是一个wifi图标,所以本身也简单的很,动画效果不过就是1→1+1→1+1+1→1+1→1这种循环,GIF来做简单到没朋友,三帧循环播放,随随便便搞个软件都能实现,即使UI小白,大概看了这种图标也会很轻蔑的不屑一顾的走开吧。
咳咳,那我们用SVG来实现吼不吼?

##1.动静分离
这里又要祭出我们的“动静分离大法”了,静态元素就是最下面的圈圈咯。然后动态元素就是上面那两条杠杠咯。
先借助AI导三部分的路径出来。

<path id="top" d=""/> <!--顶部杠杠-->
<path id="middle"  d=""/><!--中间杠杠-->
<path d=""/><!--底部圈圈-->

##2.定义基础的动画
这种一闪一闪的动画,第一时间想到的就是通过定义关键帧的透明度的改变来实现,不过这里透明度opacity是两个极值,0对应消失,1对应出现,那先把基础的动画写出来。先对时间轴进行拆分,以确定关键帧的时间点。

时间轴拆解
时间轴拆解

如上图,关键帧时间确定之后,可以着手定义CSS样式了。

<style>
@keyframes top{
0%{opacity:0}
30%{opacity:1}
70%{opacity:0}
}
@keyframes middle{
0%{opacity:0}
15%{opacity:1}
85%{opacity:0}
}
path{fill:#32b16c}
#top{animation:top 1s infinite}
#middle{animation:middle 1s infinite}
</style>

此时得到的动态SVG是下面这种

渐变的wifi动画
渐变的wifi动画

完全不是我们想要的效果~~
因为animation会自动形成过渡效果的,类似做动画时的补间,那么问题来了,我们要的可是无过渡的帧动画效果,不是这枚变淡变深的货,go on 继续,你离成功只差一个属性值了。

##3.steps参数的定义
先碎碎念一遍animation所有的属性值,animation-name|动画名称,animation-duration|一个周期的时间,animation-timing-function|动画速度曲线,animation-delay|动画延迟开始的时间,animation-iteration-count|动画播放次数,animation-direction|动画是否下一周期逆向播放,animation-play-state|动画运行状态,animation-fill-mode|动画时间外对象的状态。
我们在实际定义动画时,当然不会这么一一的去写属性名称,而是直接写属性值。码了这么多字,是想说学习要知其然更要知其所以然,即使最后会放出可以复用的代码,但能看明白,然后自己去改去做岂不妙哉。
steps参数对应的是animation-timing-function|动画速度曲线,我们最常用的就是默认的线性,或者稍微自然的ease,这里偏偏反行道而行之,steps()指定了两个参数,一个为整数值,表示跳帧动画间隔数量,第二个为start和end,默认为end,表示这种跳帧动画是在间隔的起点还是终点变化。
当然了,对于我们这个动画而言,跳帧间隔是1,所以我设置steps(1),对应动画设置变成下面这种:

#top{animation:top 1s steps(1) infinite}
#middle{animation:middle 1s steps(1) infinite}

那动画效果呢,看一下:

跳帧动画效果wifi
跳帧动画效果wifi

就是这种效果!
这里简单说一下,为什么不能设置成steps(1,start),如果让跳帧动画在间隔的起点变化,以中间形状middle为例,在0%→15%的间隔中,我们设想中是在15%的时间点发生透明度opacity变成1的跳帧动画,也就是时间间隔的终点,如果改成起点,就意味着在0%的时间点透明度就变成1了,同理,15%→85%的时间段,在这个时间段的起点15%时就发生了透明度opacity变成0的跳帧动画。
动画时间轴就变成了下面介个样子

动画时间轴拆解
动画时间轴拆解

动画效果放一下,可以对比一下:

修改steps参数后的跳帧动画
修改steps参数后的跳帧动画

很明显,中间形状出现的时间很短,得到了正好相反的效果(该出现时消失,该消失时出现)。
我们顺便对上面的代码优化一下:当我把时间轴一分为二,会发现是左右对称的

左右对称的时间轴
左右对称的时间轴

那可以通过定义逆向播放属性值alternate,然后精简关键帧,记得同时动画周期的时间也要相对缩短1/2,得到代码及注释如下:

<svg>
<style>
@keyframes top{
0%{opacity:0}
30%{opacity:1}
}
@keyframes middle{
0%{opacity:0}
15%{opacity:1}
}
path{fill:#32b16c} <!--如果要设定三种不同颜色,在#top和#middle里面单独定义一个fill值-->
#top{animation:top 0.5s steps(1) alternate infinite}
#middle{animation:middle 0.5s steps(1)  alternate infinite}
</style>
<path id="top" d=""/>
<path id="middle"  d=""/>
<path  d=""/>
</svg>

着迷于SVG的原因就在于,可以随随便便替换个颜色,比如下面这种:

三种不同颜色的wifi图标
三种不同颜色的wifi图标

##4.附赠steps延伸动画
说好的结尾彩蛋来了!
当然了,把steps属性用在我们这个SVG动画案例里着实是大材小用了,“哒哒哒”,能想起什么,没错!时钟!用steps属性实现的跳帧动画来做个闹钟的指针动画效果,这还差不多嘛。
先随随便便来一个闹钟如下:

时钟基础图形
时钟基础图形

来,跟我再念一遍,“动静分离大法”,拆成下面两个部分,记得AI里面分在不同图层,搞好命名,别把自己弄晕了。

静态图形
静态图形

指针层
指针层

导出的SVG我把代码简化一下如下:

<g id="base">
……此处为若干闹钟底层形状的组成代码……
</g>
<path d=""/><!--时针对应的路径-->
 <path d=""/><!--分针对应的路径-->

好了,现在这个闹钟里面有两个指针,就定义为时针hour和分针minute吧,下面就要给这两个指针定义旋转动画了。我们都知道,分针转一圈360度,时针才转30度(1/12)。也就是说,在定义动画周期时,hour对应的时间应该是minute的12倍。比如,我让分针旋转一圈的时间为3s,那对应时针则是36s,既然是要实现跳帧动画,记得加上steps属性。动画的CSS属性如下

<style>
@keyframes hour{
0%{transform:rotate(0)}
100%{transform:rotate(360deg)}
}
@keyframes minute{
0%{transform:rotate(0)}
100%{transform:rotate(360deg)}
}
#hour{animation:hour 36s steps(12)   infinite; transform-origin: }/*这里一定要定义旋转动画的中心点*/
#minute{animation:minute 3s steps(12) infinite;transform-origin:}
</style>

看一下动画效果如何:

时钟动画
时钟动画

嗯,哒哒哒的效果出来了,但是感觉怪怪的有没有?问题出在哪里呢?想想我们日常生活中,这种跳帧效果的只有秒针对不对?时针和分针都是均匀转速。然后我们毕竟是示范动画嘛,又不是真要做一个闹钟出来,为了得到好一点的效果,现在我让指针变换一下身份,长的作为秒针,然后模拟一下我们真实的环境,1s走一步,然后短的作为分针,那就需要改一下动画里面的属性了。

#minute{animation:minute 60s steps(60) infinite;}

秒针设置如上,动画周期为60s,steps(60)表示60个跳帧动画。
分针既然是顺滑的旋转,那就去掉steps属性,那分针转一圈是60分钟,所以动画周期就是3600s咯。

#hour{animation:hour 3600s infinite;  }

我随意截取了一段动画看看效果:

秒动画
秒动画

当然啦,勤劳的小伙伴可以把秒针,时针,分针都加上,然后我这种急性子让时间跑得快快的,就得到了下面这个动画:

加速
加速

有没有种白驹过隙感慨逝水流年的忧桑?
我的动画设置如下:

#hour{animation:hour 7200s infinite;}  /*时针动画设置*/
#minute{animation:minute 600s steps(60) infinite;}/*分针动画设置*/
#second{animation:second 10s steps(60) infinite;} /*秒针动画设置*/

总之,关于时间周期的关系好好理一下,比如时针转一圈是12个小时,所以是分针的12倍,分针是秒针的60倍。另外这里如果秒针一圈的动画时间给的太短,就看不出跳帧效果啦~
好了,关于steps的延伸动画到此为止~有好的应用再更新。