这是一组效果非常炫酷的基于GSAP的SVG Loader加载动画特效。这组SVG加载动画特效共有7种效果,分别使用GSAP对SVG进行操纵,制作出各种炫酷的Loading加载动画效果。
这些SVG加载动画效果依赖于一个非常强大的插件-DrawSVGPlugin,该插件可以帮助你创建高质量的SVG动画和特效。
注意,这个效果中的例子你可以在本地计算机中自由在查看效果,但是如果你要将这些效果用于服务器中,需要注册一个GreenSock的会员账号。
使用方法
下面来看一下这些SVG加载动画是如何制作的。这里充分利用了GSAP的测序工具TimelineMax和DrawSVGPlugin。DrawSVGPlugin插件用于逐步显示或隐藏SVG的描边,这可以非常方便的制作Loader效果。
要了解更多关于GSAP和其它工具,建议查看下面的文章:
HTML结构
下面来看一下第一种效果Jump Loader,这是一个非常有趣的特效-一条半圆形的线条就像从液体中跳出来然后再潜如液体中,很有鲤鱼跳龙门的感觉。该效果的HTML结构如下:
<div id="container"> <svg id="loader" width="200px" height="200px" viewBox="0 0 200 200"> <path id="jump" fill="none" stroke="#2d2d2d" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M47.5,94.3c0-23.5,19.9-42.5,44.5-42.5s44.5,19,44.5,42.5" /> <g stroke="#2d2d2d" stroke-width="1"> <ellipse id="circleL" fill="none" stroke-miterlimit="10" cx="47.2" cy="95.6" rx="10.7" ry="2.7" /> <ellipse id="circleR" fill="none" stroke-miterlimit="10" cx="136.2" cy="95.6" rx="10.7" ry="2.7" /> </g> </svg> </div>
这个加载动画中的SVG图形是在Adobe Illustrator中创建的。你也可以使用其它工具如:Sketch(只能在Mac上使用)或Inkscape来制作。这个SVG图形由一个半圆形的线条和两个椭圆图形组成,如下图所示。并且背景设置为红色的方块,原因是当你从Illustrator选择和拷贝SVG图形到HTML页面中的时候,SVG的viewBox
的尺寸由整个选择的图形的大小来决定。也就是说,如果你只选择线条和椭圆,那么SVG的viewBox的尺寸仅仅是你选择额图形形成的一个组的大小。这样就没有多余的空间可以进行SVG动画了。
要创建一个大的SVG动画区域,可以像上面这样创建一个大的矩形区域,然后将这个区域一起拷贝到HTML文件中,之后就可以将该矩形区域的代码从SVG代码中删除,只留下线条和椭圆的代码,但是这时viewBox
的尺寸仍然是原来矩形的尺寸。
结构和布局
首先创建一些变量来引用HTML元素,这种方法可以将引用缓存起来,还可以在你需要这些HTML元素引用的时候不必重复的查找HTML代码。但是要注意的是这种方法会占用移动手机的宝贵的内存资源。所以是否使用这种方法由你决定。
var container = document.getElementById('container'); var loader = document.getElementById('loader'); var circleL = document.getElementById('circleL'); var circleR = document.getElementById('circleR'); var jump = document.getElementById('jump');
在效果中线条有一个反射的倒影,在SVG图像中没有创建它。可以在JS代码中使用克隆函数将线条克隆一份出来。然后在后面将它翻转并降低其透明度。
var jumpRef = jump.cloneNode(); loader.appendChild(jumpRef);
下面使用GSAP来简单的居中定位。这里要使用TweenMax来将包裹容器和它里面的SVG居中对齐,这样做的原因是居中只需要设置一次,而且它不必成为动画序列的一部分。代码中xPercent
和yPercent
参数等效于CSS的transform: translate(-50%, -50%)
,并且包含了所有的浏览器厂商的前缀。
TweenMax.set([container, loader], { position: 'absolute', top: '50%', left: '50%', xPercent: -50, yPercent: -50 })
最后,在布局中使用TweenMax来翻转倒影线条。这可以通过改变它的Y轴transform origin
到110%,并使用负的scaleY值来实现。
TweenMax.set(jumpRef, { transformOrigin: '50% 110%', scaleY: -1, alpha: 0.05 })
制作跳跃动画
下面将要使用TimelineMax和链式动画方式来制作线条跳跃动画特效。
实现要创建一个TimelineMax的新的实例对象。TimelineMax实例对象可以接收一组参数和事件,如:延迟、yoyo
、onComplete
等。这里设置无限重复跳动效果:设置repeat
为-1。
var myTimeline = new TimelineMax({ repeat: -1 });
下面就可以开始制作动画序列了。首先使用GSAP的DrawSVGPluginl来将线条和它的倒影分开,分格的空间值设置为一个区间,这里设置为0% 0%
意思是区间的开始和结束位置都设置为0%,并且它们都是从左向右进行绘制。
这里还使用TweenMax的内置语法attr
来设置了椭圆形波浪效果X和Y轴半径都为0(不可见)。注意第一个set
函数之后没有分号,这是链式编程的写法。
myTimeline.set([jump, jumpRef], { drawSVG:'0% 0%' }) .set([circleL, circleR], { attr: { rx: 0, ry: 0, } })
上面的代码只是设置了一些值,真正的动画效果还没有开始。动画时间轴将无限循环的执行,所以每次动画开始时都必须调用原始的初始值。现在时间轴的持续时间仍然是0。
两条线条都会被动画到它们总长度的30%,DrawSVG的值0% 30%
表示动画开始的区间是0%,当前线条的长度是总长度的30%,如下图所示。同时还使用一个线性的ease效果来制作一个平滑的绘制线条效果。
.to([jump, jumpRef], 0.4, { drawSVG: '0% 30%', ease: Linear.easeNone })
接下来,就要通过rx
和ry
属性使左边的椭圆形波浪放大。如果它们都使用相同的值如+=30
那么椭圆就会均匀的放大,这种设置会使波浪没有立体感,所以这里将两个值分别设置为不同的值。
在这个动画的结束处添加了一个额外的offset
参数--=0.1
,这个设置的意思是该动画的时间被设置为0.3秒(0.4-0.1=0.3秒),因为上一个to
动画的时间是0.4秒。
.to(circleL, 2, { attr:{rx:'+=30', ry:'+=10' }, alpha:0, ease:Power1.easeOut }, '-=0.1')
下面继续制作动画,现在线条已经向前运动,这时它们的尾部要开始出现并执行动画。注意这次的动画时间是-=1.9
,DrawSVG
的值设置为50% 80%
意思是30%的线条仍然可见,线条从50%处开始,80%处结束。
.to([jump, jumpRef], 1, { drawSVG:'50% 80%', ease:Linear.easeNone }, '-=1.9')
最后,要使线条运动到100%处。
.to([jump, jumpRef], 0.7, { drawSVG:'100% 100%', ease:Linear.easeNone }, '-=0.9')
不要忘记还有右边的椭圆形波浪,它会被像左边波浪效果一样被执行动画。
.to(circleR, 2, { attr:{rx:'+=30', ry:'+=10' }, alpha:0, ease:Power1.easeOut }, '-=.5'); myTimeline.timeScale(3);
当这个加载动画执行的时候,它会无限进行循环。最后的myTimeline.timescale(3);
是用于调整整个动画的时间,使动画看起来更加自然。
完整代码
下面是Jump Loader加载动画效果的完整代码:
var container = document.getElementById('container'); var loader = document.getElementById('loader'); var circleL = document.getElementById('circleL'); var circleR = document.getElementById('circleR'); var jump = document.getElementById('jump'); var jumpRef = jump.cloneNode(); loader.appendChild(jumpRef); TweenMax.set([container, loader], { position: 'absolute', top:'50%', left: '50%', xPercent: -50, yPercent: -50 }) TweenMax.set(jumpRef, { transformOrigin: '50% 110%', scaleY: -1, alpha: 0.05 }) var tl = new TimelineMax({ repeat: -1, yoyo: false }); tl.timeScale(3); tl.set([jump, jumpRef], { drawSVG: '0% 0%' }) .set([circleL, circleR], { attr: { rx: 0, ry: 0, } }) .to([jump, jumpRef], 0.4, { drawSVG: '0% 30%', ease: Linear.easeNone }) .to(circleL, 2, { attr: { rx: '+=30', ry: '+=10' }, alpha: 0, ease: Power1.easeOut }, '-=0.1') .to([jump, jumpRef], 1, { drawSVG: '50% 80%', ease: Linear.easeNone }, '-=1.9') .to([jump, jumpRef], 0.7, { drawSVG: '100% 100%', ease: Linear.easeNone }, '-=0.9') .to(circleR, 2, { attr: { rx: '+=30', ry: '+=10' }, alpha: 0, ease: Power1.easeOut }, '-=.5')