阅读 783

设计师的专属魔法,用SVG动画重现布尔运算的设计过程

这是在作图时突然迸发的灵感(是的,偶尔也会有那么一瞬间头脑开窍),作为设计师小伙伴们,平时用的最多的应该是布尔运算吧,基础图形的加加减减,得到任意的形状。就不说经典的Apple了,比如网易云音乐图标,你如果直接放上这个,似乎没什么。


但放上布尔运算过程的设计稿(所有基础图形的轮廓),瞬间高大上起来,满满的设计感。


所以在做矢量图的过程就突然想到如果能用SVG结合CSS3的动效来还原这个设计过程,也不失为一个好玩的效果,当然了,不会那么巧刚好用到所有的四种运算,只是用动画过程演示一遍,此为目的。因为自己的底子就很弱,所以选了一个临摹的图形,众位客官凑合看吧。

1.准备工作——图形分层

每次在做SVG动效之前,都会给自己一点时间思考一下动画完成的思路,以及用什么属性来实现,正所谓多点思考,少点劳作,或者换句话说,“不能用战术的勤奋来代替战略的懒惰”。
先放一张成品的效果图,如下,就是这只萌萌的小象


AI中做布尔运算虽然用路径查找器极其方便,且能切割,任意玩,但是修改起来却没有PS那么方便,给做完运算后的调整不是很方便的说。比如十几甚至更多个形状的布尔运算在PS里玩起来还算轻松,左挪右挪上层下层的调节么有压力,在AI里那要被玩坏了。所以第一步,要在AI里做好分层。注明一点,这些是要在作图之前就确定的。
我把小象分成三个部分,身体、头部和尾巴,目的就是为了减少每个部分的基本形状的数量。
AI中进行过布尔运算后的形状导出后是得到的结果的路径,这就不欢乐了,举个简单的例子:


上面两个圆形,相交之后得到的形状,导出后是<path d="">,完全不见两个圆形<circle>的踪迹,既然我们是还原过程,过程,就需要把原运算前的路径保留,怎么破?在进行运算之前原位复制到新的图层中呗。以小象的身体为例,我保留了两个图层,运算后和运算前的,这些路径都是我需要用到的。

2.创建图形过程的动画

鉴于自己这渣渣一般的水平,图形加减那一套过程就不拿出来嘚瑟了,还是留着自家珍藏吧,这里只说如何用动画表现出来。各位设计师回想一下自己的创建基本形状的过程,是不是选择形状后在画布进行鼠标拖动就可以了,嗯,这里我们主要实现的就是鼠标拖动的动画过程。来看下面这张图(不要给我讲你是按着alt键巴拉巴拉的,不管,要不这动画没法做了 ~~(>_<)~~):


从左上角到右下角的拖动过程就是图形的创建过程,而且在创建的过程中,图形是逐渐从无到有,从小到大的。好了,废话了半天,不不,是抛砖引玉,这就是我们实现创建图形过程的动画思路。

@keyframes draw{
0%{transform:scale(0,0);transform-origin:left top}
100%{transform:scale(1,1);transform-origin:left top}
}  
/*通用绘制过程的动画定义*/复制代码

经过分析我们得出,缩放变形transform:scale()是实现这种效果的最佳方案,这里唯一要注意的是关于变形的基点,前面在涉及旋转动画中,更多的定义是transform-origin:center center,也就是以圆心为基点,而这里定义的是左上角,也就是left top,其实CSS的一些语法真的算是很简单了,英语入门级。另外这里对应的left和top的值是相对位置,这也是为什么能把draw定义成通用的原因。
下面这张图形虚线部分是为了得到身体部分创建的所有基础图形,实色填充的部分即为最后需要的身体部分。

基础图形是由5个圆形和1个矩形共同组成的。我进行了标号。


对于身体部分,是4个圆形和1个矩形与1个基础圆形进行相减得到的。为了让动画过程更形象,让基础圆形进行了实色填充,其他形状用虚线来表示。根据上面动画的定义,先来实现基础图形的创建过程,CSS部分如下:

<style>
@keyframes draw{
0%{transform:scale(0,0);transform-origin:left top}
100%{transform:scale(1,1);transform-origin:left top}
} 
#circle0{animation:draw 1s ease;fill:#414c68;}/*基础形状用实色填充*/
#circle1{animation:draw 1s ease 1s backwards;}
#circle2{animation:draw 1s ease 2s backwards;}
#circle3{animation:draw 1s ease 3s backwards;}
#circle4{animation:draw 1s ease 4s backwards;}
#rect1{animation:draw 1s ease 5s backwards;}
.sketch{stroke:#c0f1ff;stroke-width:2;fill:none}/*其他形状用描边*/
</style>复制代码

SVG部分简化如下(去掉了和形状尺寸位置相关的属性定义):

<circle id="circle0"/> <!--基础形状-->
<g class="sketch">  <!--其他形状-->
<circle id="circle1" />
<circle id="circle2" />
<circle id="circle3"/>
<circle id="circle4"/>
<rect id="rect1"/>
</g>复制代码

简单解释一下,动画属性定义那里拿这个#circle1{animation:draw 1s ease 1s backwards;}为例,第一个1s是绘制时间,第二个1s是延迟时间,为了让图形呈现出依次创建的过程,所以延迟时间是递增的。backwards这个属性一定要定义,当我们给动画定义了延迟时,我们需要定义动画时间之外对象的状态(animation-fill-mode),backwards表示动画开始前应用开始属性值,也就是我们定义的scale(0,0),换句话说,是不显示的,这里也可以定义成both,对这个动画效果而言,没有区别。
现在看一下动画效果:


嗯,基本重现了创建了基础图形的过程。那么下一部分来了,怎么才能过渡到运算之后的形状呢?

3.运算过程的动画

在做这个动画伊始,我想到的是把相减的图形转化成蒙版,能行不?绝对能行,但实在是太麻烦了。记得我们还保留了运算后的图形放到了单独的图层中吧?这时,需要它粉墨登场了,然后其他的图形怎么办?集体消失!
关于消失的方法也有很多种,随便来个顺手的就行了,我准备用蒙版。为了实现组合图形消失以及运算后的图形出现的过程,不得已,又定义了两个动画,其实做到这里的时候,已经很后悔了,远不如好好学学AE,在AE里实现,但自己挖的坑,含着泪也要跳进去再努力爬出来啊,善始善终,硬着头皮继续做吧。流着泪补充了下面的动画定义:

@keyframes skip{
0%{opacity:0}
100%{opacity:1}
} /*这是为要登场的图形准备的*/
@keyframes combine{
0%{fill:#FFFFFF}
100%{fill:#000000}
}/*这是为要退出舞台的图形准备的*/

.skip{animation:skip 1s  6s both; fill:#414c68}
.combine{animation:combine 1s 6s both;}复制代码

以及:

<mask id="shade"><rect x="0" y="0" width="800" height="600" id="combine"/></mask> <!--蒙版定义-->
<g mask="url(#shade)">……</g>
<path class="skip" d=""/><!--组合后的形状-->复制代码

<g mask="url(#shade)">是把所有的图形又组合后,使用这个蒙版。唯一值得欣慰的是skip和combine这两个动画可以被复用。
插播一个小知识点,关于利用蒙版的渐隐动画,是不能用0%{opacity:0} 100%{opacity:1} 然后填充黑色fill:#000000这种表面上看上去是蒙版渐现的方式来实现,是因为当不给蒙版定义颜色时,蒙版会被默认为黑色,因此即使开始定义了透明度为0,也会被当做黑色处理。如果实在要用的话,就套两层蒙版,一层黑色的透明度改变,下面一层白色实色底。我只截变化的那一部分动画来看一下:


似乎衔接的还不错哟。

剩下的工作就是体力活了呃,需要把头部的动画和尾巴的动画补充上,没有什么特殊的,延迟的时间别弄错了就行,这里就不说了吧。最后得到的统一的动画是这个样子的:


与理想中那种满满的设计感有差异,不过还好。下面试着来优化一下,上个色吧。

4.颜色填充过程

颜色填充的过程,与这个展示绘制动画过程没有什么毛线关系,就是为了好看!好看!我还能说什么呢?说什么显示填色的过程,鬼,对于怎么展示渐变填充完美没有思路,我就利用了一下蒙版,把已经填充好的图形先用蒙版盖起来,让你们看不见看不见,然后在适当的时间,蒙版逐渐移动,露出填充好颜色图形。为了让蒙版显示的效果更加自然,这里我用渐变色对蒙版进行了填充。图示如下:

<defs>
<linearGradient id="gradient3"  x1="0" y1="0" x2="0" y2="600">
  <stop offset="0" stop-color="#ffffff"/>
  <stop offset="0.1" stop-color="#000000"/>
</linearGradient>
</defs>    <!--定义的渐变类型-->复制代码

最后得到的效果如下:

另外,狠狠的告诫自己,下次再也不做这种费劲巴拉但不酷炫的效果了。

关注下面的标签,发现更多相似文章
评论