UI 设计师福利,svg 描边动画效果,零代码基础手把手教你完成

2,110 阅读17分钟

svg无疑是现在前端比较热门的图形格式,且很实现很多动画效果,以下发布的,为svg描边效果的教程。


动效展示(录屏转gif).gif

自己虽然有css代码基础,但对于css动画绝对属于小白一只,且前端的JavaScript更是一窍不通,但svg的描边动画是在过于神奇,毕竟是用代码生成的,于是在svg基础动画入门之后,硬着头皮开始啃网上关于svg描边动画的文章,林林总总的看了有十多篇,虽然有一些是不涉及js的,但是要么动画效果太单一,比如只是一条连续的线,要么对时间和速度的控制不精确,比如设定一个极大值之类,虽然也是动画,但自主性太差,而路径长度的准确获取一般都是用js来实现的(下面会提到路径长度的重要性),在总结了一系列的文章之后,终于有了下面这个教程,分步骤拆解一个svg动画,可以在没有js基础的情况下实现动态描边效果,以下提供的代码,可以通过替换里面的几个固定值来实现各种创意描边效果(只有你想不到,没有代码做不到),具体需要替换哪些值,如何替换,替换成什么数值,也会一一说明。你甚至不用去深度纠结里面代码的含义,而只是把它当成一个范本,当然,必须要知道且简单易懂的,我会稍作解释。
在这里分享出来,希望给对svg动画感兴趣的零代码基础的设计师提供一点便利。来,深吸一口气,开始,记住,不要被代码吓到,因为它们不需要你敲出来。

1.先用AI做出基础的描边图形

这一步,对于每个UI来说,都是非常容易的事情。这里一定要用AI,不可用PS,如果AI不会用的话,请绕道,下面的教程没有意义。
在真正开始作图之前,把思路理清楚,要做哪种图形,动画效果是怎样的。我的思路是做一个动态描边的键盘,我把它分成5个部分,①键盘的矩形外轮廓 ②小方块键盘按键 ③回车键 ④空格键(把回车键和空格键单独绘制,是希望制作一点与众不同的效果)⑤ 键盘线
这五个部分一定要建在5个不同图层,这样在AI导出svg代码时才不至于自己把自己给看晕了。
对应动画也是绘制这5个部分,且每个部分的动画完成之后再开始下一段动画。
有了基本思路之后,开始在AI里进行基本图形的绘制。

1.1 绘制外部轮廓

画键盘外部的轮廓,图层命名border,由于需要获得是路径,不是闭合的矩形,所以我的图形绘制用了钢笔,但起点和终点是重合的,所以即使它看上去是一个矩形,但却不是矩形工具生成的。(参考线可以忽略,不过以参考线为基准绘制图形可以让最后的svg代码比较清爽,不至于生成很多位小数点的那种。)


键盘-border.png

你绘制路径时的走向也是你动画的走向,所以考虑清楚再绘制。图层命名尽量用英文。

1.2 绘制小方块按键

同样的思路,继续画小的按键,依旧是用钢笔工具。因为我对按键动画的要求是全部同步,所以把它们放到了同一个图层keyboard中,这里,如果你希望按键是一个一个单独呈现动画效果的话,就需要建立在不同的图层中(太过繁琐,且动画时间会太长,不推荐),同理,如果你希望按键分成上下两排分别呈现不同的动画,就放到两个图层里。


键盘-keyboard.png

1.3 绘制回车键

这里把回车键单独拿出来,并不是因为颜色的问题,而是回车键的路径长度要比小的按键要长很多,我要赋给它更长的动画时间,前面轮廓和按钮的绘制我是逆时针方向,回车键绘制时我采用了顺时针方向,给动画一点小小不同的变化,这个图层我命名enter。


键盘-enterkey.png

1.4 绘制空格键

有了上面的铺垫,空格键就不用多说了,这个图层我命名space。


键盘-space.png

1.5 绘制键盘线

这个图层我命名line。


键盘-line.png

这是所有的图形元素分布的图层。


AI创建时图层及命名.png

图形的分层非常重要,不同的动画拆分分布到不同图层,图层做好命名,生成的svg代码会非常清晰。一定要用AI来完成绘制。

2.把AI导出SVG并进一步整理

一切准备就绪,我们来生成一个svg文件,在存储为的弹出框里选择svg格式,确定之后在面板中选择“SVG代码”,得到一个文本文档,里面是所有的AI转SVG后的代码。


复制svg代码.png

当然,可以直接保存成svg格式,但我个人嫌弃AI直接生成的SVG里有冗余代码,不够清爽,所以我习惯性的把和svg相关的代码部分保存到我预置的一个SVG文档。我贴上我的svg代码,这里有个小小的替换,AI生成的svg代码是<g id="">,这里统一改成了<g class="">,是为了方便后面定义CSS样式的时候使用类。这一步替换不是必须的,如果不替换的话,css代码那里要对应以#开头,这个是个人的喜好问题(我一般很少用id标签),对于有CSS基础的人来说,怎么都行,如果是小白,还是尽量这里就更换。

<svg  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  width="1000" height="1000"><g class="border">
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="12" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    200,200 100,200 100,400 500,400 500,200 200,200     "/>
</g>
<g class="keyboard">
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    180,224 140,224 140,264 180,264 180,224     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    250,224 210,224 210,264 250,264 250,224     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    320,224 280,224 280,264 320,264 320,224     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    390,224 350,224 350,264 390,264 390,224     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    180,284 140,284 140,324 180,324 180,284     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    250,284 210,284 210,324 250,324 250,284     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    320,284 280,284 280,324 320,324 320,284     "/>
</g>
<g class="enter">
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#F2856B" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    420,224 460,224 460,324 350,324 350,284 420,284 420,224     "/>
</g>
<g class="space">

    <polyline fill="none" stroke="#82D8D5" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    460,348 140,348 140,376 460,376 460,348     "/>
</g>
<g class="line">
<path fill="none" stroke="#FFBB4D" stroke-width="12" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
    M187.3,192c0,0,29.3-43.3,76-46S372,167.3,405,112.7S424.7,30,424.7,30"/>
</g></svg>

这一堆密密麻麻的代码是不是看着就头晕,跟我做,甩头,保持微笑,这都是AI自动生成的,而且如果你去看的话,会发现每个g对应我们AI的一个图层,so easy。
这时,如果把这些代码复制到一个txt文档中,然后改后缀名为.svg,用任一浏览器打开查看(ie也可),就已经能看到键盘图形了(如果是第一次接触svg的设计师们,恭喜你,已经实现了svg零突破了,只是,它是静态的,不要急,往下慢慢看)。

平面转UI的设计师,在svg领域,你们更有优势,也可以使用AI另存为的svg格式的文件用文本编辑器打开编辑。

3.CSS样式的设定

现在在刚才的svg代码里插入下面的CSS代码。

<style>
@keyframes dash {
to {
stroke-dashoffset: 0;
}
}
</style>

这一段代码简单解释一下,就是通过设定关键帧,来让描边虚线的偏移值从设定值到0,这是我们描边动画的关键,通常这段代码一定会出现,且不用理会。如果没有svg基础的话,你可能会问,什么是偏移值,哪里来的描边虚线,我明明都是实线,所以我要说的是:不想解释!因为不知道从何说起了,涉及到描边属性,以及这个动画的实现原理,巴拉巴拉,网上好多,自行查找,我们直接一点,拿来主义。因为对于小白来说,更需要知道的是——关于css代码插入的位置:
放到第一个分组标签<g>之前。
这里不用担心,我会在文章的最后贴出全部的代码及注释,告诉你哪里需要修改替换。

下面这两段代码需要简单解释一下,这里并没有贴出全部代码,而是两段动画,一个是键盘外轮廓,一个是按键,我设定的动画是第一个动画完成之后第二个动画开始。

.border{
stroke-dasharray: 1200;
stroke-dashoffset: 1200; 
animation: dash 1.5s linear forwards;
}
.keyboard{
stroke-dasharray: 160;
stroke-dashoffset: 160;
animation: dash 1s linear forwards; 
animation-delay:1.5s;  
}

这两段代码类名那里不用解释了,.border和.keyboard都是刚才对应的svg代码中<g class="">的类名,换句话说,就是我们AI对应的图层的命名,所以这里就很好理解了,每段CSS代码都对应控制自己的图形元素,再继续看stroke-dasharray(虚线间隔)和 stroke-dashoffset(虚线偏移值),border(即键盘外轮廓)和keyboard(键盘按键)定义了不同的值,那这个值从何而来,很简单,它们对应的都是图形路径的长度,这时,祭出我们的AI神器。


文档信息-路径长度.png

从图中可以看出,当选中一段路径,查看文档信息时,里面有一个AI自动计算的路径值。这里重点说一下,之所以这个svg动画效果不需要js且可以精确控制速度,这个值功不可没。

在我看的其他关于这种动画效果制作的文章里,很多是给stroke-dasharray和 stroke-dashoffset设定了极大值,这样做的后果是无法控制动画在需要的时间点开始以及动画的速度,或者是用JavaScript代码var path = document.querySelector('path');
var length = path.getTotalLength();来获取路径长度,现在,我们可以不受限制的使用AI的文档信息直接查看,非常方便。
我们要做的,就是给stroke-dasharray和 stroke-dashoffset都设定成路径长度对应的值。对于矩形,这似乎不是什么了不起的功能,毕竟知道对应的坐标值,可以轻松算出,但对于曲线类的复杂路径,可是非常有用的。(另外,如果你获得的路径值是一个小数,你可以把它修正成一个略大一些的整数值,但不要往小里修正,会导致动画伊始出现一些起始点。)

通过以上的说明,你应该已经明白了, border的stroke-dasharray: 1200;和stroke-dashoffset: 1200;这个1200就是border的路径长度,那keyboard对应的160呢?当然是每个按键的路径长度了,因为我要做的是小按键同步一起的动画效果,所以只取单独一个按键的路径长度。

这句代码animation: dash 1.5s linear forwards;几乎也是通用的,不用修改(forwards改成indefinite即动画无限循环),需要你设定的就是时间值,border设定1.5s即1.5秒,也就是我希望绘制border需要的时间,同理,按键是1秒绘制完成,因为考虑到按键的路径比较短,所以时间让它快了一些,具体自己随意设定,你就是魔术师。

animation-delay:1.5s; 来看这句代码,为什么它只在keyboard的设定中出现?因为我希望一开始就直接加载动画,如果希望动画3秒后开始,聪明的你一定知道,这时,可以给border加上animation-delay:1.5s;来实现延时加载,对,animation-delay就是延时的意思。那给keyboard设定延时开始的时间是1.5秒之后,这个值从何而来?那就是border动画需要的时间,用你会抽象立体空间的大脑想象一下,如果给keyboard设定延时开始的时间是1秒,那意味着第一段border的动画还没结束,keyboard的动画就开始了,如果给keyboard设定延时开始的时间是2秒,那第一段border的动画结束后0.5秒之后第二段keyboard的动画才会开始。那第三段以及以后的动画的css的设定,就很容易了吧,无非animation-delay需要简单计算一下,即上一段动画的延迟开始时间(animation-delay的设定)加上一段动画的持续时间 (animation里关于时间的设置)。我们就是通过这些设定,来实现各种动画效果的。所以我说可以精确控制动画时间和开始时间,也是这个原因。代码的顺序很重要,不要把 animation-delay:放到animation:之前,这样会不起作用

以上代码你可以简单的理解成,设定完成绘制路径长度(根据文档信息提供设定)需要的时间(自己设定,可根据数值大小控制快慢)以及开始的时间。

写到这里,其实所有的工作都已经完成,用chrome浏览器打开看看效果吧。

现在附上所有的代码如下并提前说明,<!-- -->和/ /是我写的注释文件,来帮助你理解,你copy代码的时候,可以删除。

<svg  xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"  width="1000" height="1000">
<!--以下为css样式文件插入的位置-->
<style>
@keyframes dash {
to {
stroke-dashoffset: 0;  /* 固定动画设定,不用修改 */
}
}
.border{
stroke-dasharray: 1200;
stroke-dashoffset: 1200; 
animation: dash 1.5s linear forwards;/* 设定键盘外轮廓border的动画时间为1.5s */
}
.keyboard{
stroke-dasharray: 160;
stroke-dashoffset: 160;
animation: dash 1s linear forwards; /* 设定每个小按键的动画时间为1s,且同步*/ 
animation-delay:1.5s; /* 设定动画延迟开始的时间为border的动画完成时间,以确保动画的连续性,但一定要把animation-delay的设定放到animation之后*/  
}
.enter{
stroke-dasharray: 420;
stroke-dashoffset:420;
animation: dash 1.5s linear forwards;
animation-delay:2.5s; /* 延迟开始时间=上个动画的延迟开始时间+上个动画的持续时间 即2.5=keyboard的1+1.5*/  
}
.space{
stroke-dasharray: 700;
stroke-dashoffset:700;
animation: dash 1s linear forwards;
animation-delay:4s;
}
.line{
stroke-dasharray: 340;
stroke-dashoffset:340;
animation: dash 1s linear forwards;
animation-delay:5s;
}
</style>
<!--以上为css样式文件插入的位置-->
<g class="border">
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="12" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    200,200 100,200 100,400 500,400 500,200 200,200     "/> <!-- 键盘外轮廓路径长度1200-->
</g>
<g class="keyboard"><!-- 每个小键盘格的路径长度160-->
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    180,224 140,224 140,264 180,264 180,224     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    250,224 210,224 210,264 250,264 250,224     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    320,224 280,224 280,264 320,264 320,224     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    390,224 350,224 350,264 390,264 390,224     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    180,284 140,284 140,324 180,324 180,284     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    250,284 210,284 210,324 250,324 250,284     "/>
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#5AC5C1" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    320,284 280,284 280,324 320,324 320,284     "/>
</g>
<g class="enter">
<polyline fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#F2856B" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    420,224 460,224 460,324 350,324 350,284 420,284 420,224     "/><!-- 回车键路径长度420 -->
</g>
<g class="space">
<polyline fill="none" stroke="#82D8D5" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
    460,348 140,348 140,376 460,376 460,348     "/><!-- 空格键路径长度696,去看上面的css的设置,我设定了800,原则:可大,勿小 -->
</g>
<g class="line"><!-- 键盘线路径长度333-->
<path fill="none" stroke="#FFBB4D" stroke-width="12" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
    M187.3,192c0,0,29.3-43.3,76-46S372,167.3,405,112.7S424.7,30,424.7,30"/>
</g>
</svg>

以上是svg动态描边效果的所有代码。因为不知道怎么转成gif,所以就不贴图了,录屏又太麻烦(有知道的也请告诉我转换方法,多谢),直接点击看效果吧。
demo查看
现在可以发挥你无穷无尽的想象力,来做各种动画了,比如常见的动态签名等等。
有小伙伴们有不明白的,欢迎留言,我会进行解答,如果贴上代码,我也会尽量帮你修改。
PS:已补充上录屏后转的gif文件,但不够清晰。