逐帧动画实现的四种方式
逐帧动画实现CSS3 or JavaScript
我们经常会在H5页面中看到一段序列帧动画,最近小编对此实现方法非常感兴趣,就总结了实现逐帧动画常用的几种实现方法。比如,现在需要实现这个小动画
一、GIF动图
打开PS6,点击窗口→时间轴,在时间轴窗口中有6张不同的图片,通过一帧一帧的播放来实现这个动画。
GIF动画优缺点:
好处:实现简单、可维护性高、工作成本低
缺点:只适合简单的动画效果,不能动态控制动画
在实际的项目中,我们往往根据需求而需要把动画做的更加灵活,那就不是gif动图所能完成的了。下面,我们先探讨有哪些技术可以实现我所说的功能~~~
二、使用CSS3动画
(1)通过切换6张图片的方式来实现,具体代码实现参考如下(篇幅考虑仅列出webkit的写法):
#anim{width:120px; height:120px; position: absolute; top: 50%; left: 50%; margin-top: -60px; margin-left: -60px; -webkit-animation: auto-circle 0.5s step-end infinite; display: none;} @-webkit-keyframes auto-circle{ 0%{background-image:url(images/anim-01.png);} 20%{background-image:url(images/anim-02.png);} 40%{background-image:url(images/anim-03.png);} 60%{background-image:url(images/anim-04.png);} 80%{background-image:url(images/anim-05.png);} 100%{background-image:url(images/anim-06.png);} }
演示demo链接
6张图片合成1张,通过切换背景图片位置来实现,具体代码实现参考如下(篇幅考虑仅列出webkit的写法):
#anim{ background-image: url(images/anim.png); width:120px; height:120px; position: absolute; top: 50%; left: 50%; margin-top: -60px; margin-left: -60px; -webkit-animation: auto-circle 0.5s steps(5) infinite; } @-webkit-keyframes auto-circle{ 100%{background-position-x: 600px;} }
演示demo链接
当然,用雪碧图+CSS3实现还有一些其他的方法:
#anim{ background-image: url(images/anim.png); width:120px; height:120px; position: absolute; top: 50%; left: 50%; margin-top: -60px; margin-left: -60px; -webkit-animation: auto-circle 0.5s step-end infinite; } @-webkit-keyframes auto-circle{ 0%{background-position-x: 0;} 20%{background-position-x: 120px;} 40%{background-position-x: 240px;} 60%{ background-position-x: 360px;} 80%{background-position-x: 480px;} 100%{background-position-x: 600px;} }
演示demo链接
#animbg{ width:120px; height:120px; position: absolute; top: 50%; left: 50%; margin-top: -60px; margin-left: -60px; overflow: hidden; } #anim{-webkit-animation: auto-circle 0.5s step-end infinite;;} @-webkit-keyframes auto-circle{ 0%{-webkit-transform:translate3d(0,0,0);} 20%{-webkit-transform:translate3d(-120px,0,0);} 40%{-webkit-transform:translate3d(-240px,0,0);} 60%{-webkit-transform:translate3d(-360px,0,0);} 80%{-webkit-transform:translate3d(-480px,0,0);} 100%{-webkit-transform:translate3d(-600px,0,0);} }
演示demo链接
分析使用6张图片和1张雪碧图这两种方式
方式一:
实现起来会比较简单,但带来额外的5个请求数
6张图片总大小为:56.5k
加载时间:
方式二:
需要设计雪碧图,并量取背景位置,请求数少
雪碧图大小为:44.9k
加载时间:
由上面的分析可以看出,多张图片合成的雪碧图比6张图片还少 11.6k 外,还可以减少5个HTTP请求,并且加载时间也会大大减少,当然加载时间有时也会根据用户当前所处的网络环境而有所不同,综上所述,还是使用切换背景位置方式是比较好的。
三:使用JavaScript操作CSS属性
(1)采用6张图片依次显隐的方式,具体代码实现参考如下:
$(function(){ var animImg = 1; var animImages = setInterval(function () { animImg++; if (animImg >= 7) { animImg = 1; } $(".animImg").hide(); $(".animImg" + animImg).show(); }, 100); });
演示demo链接
(2)采用雪碧图,通过javascript不断的改变帧图片的background-position,具体代码实现参考如下:
(function(){ window.frameAnimation = { anims:(function(){ /* obj=>需要执行背景动画的对象; width:图片的总宽度 steps=>需要的帧数; eachtime=>一次完整动画需要的时间; times=>动画执行的次数 0表示无限反复 */ return function(obj,width,steps,eachtime,times, callback){ var runing = false; var handler = null; //obj,width,steps,eachtime,times定时器 var step = 0; //当前帧 var time = 0; //当前第几轮 var speed = eachtime*500/steps; //间隔时间 var oneStepWidth = width/steps; function _play(){ if(step >= steps){ step = 0; time++; } if(0 == times || time < times){ obj.css('background-position', -oneStepWidth * step + 'px 0px'); step++; }else{ control.stop(); callback && callback(); } } var control = { start:function(){ if(!runing){ runing = true; step = time = 0; handler = setInterval(_play, speed); } return this; } ,stop:function(restart){ if(runing){ runing = false; if(handler){ clearInterval(handler); handler = null; } if(restart){ obj.css('background-position', '0 0'); step = 0; time = 0; } } } ,dispose:function(){ this.stop(); //console.log('anim dispose'); } }; return control; } })() } })(window); function play(){ var anim = frameAnimation.anims($('#anim'),720,6,1,0); anim.start(); }
演示demo链接
四、使用Canvas
说到帧动画,很容易就联想到canvas,将图片绘制到canvas上面,不断重绘就能得到我们想要的效果。使用canvas的好处是,只要有一个基于canvas模拟帧动画的类库,就可以随意使用。操作JavaScript比操作css要灵活,可以传递各种参数实现不同的要求,还可以使用回调函数来设置动画结束时的操作。缺点是老式浏览器不兼容canvas,而且如果需求简单的话,使用canvas有些大材小用。一个最简单的循环动画类如下所示:
var loader; var img; var stage; var w; var h; window.onload=function(){ stage = new createjs.Stage('animCanvas');//创建舞台 w=stage.canvas.width; h=stage.canvas.height; $('#animCanvas').css({'height':120+'px','width':120+'px'});//适配用 manifest = [ {src: 'anim.png', id: 'img'}, ];//预加载 loader = new createjs.LoadQueue(false); loader.addEventListener('complete', handleComplete);//加载完成 调用handleComplete函数 loader.addEventListener('progress', handleFileProgress);//加载完成 调用handleFileProgress函数 loader.loadManifest(manifest, true, 'images/'); } function handleComplete(){//加载完成调用函数 var spriteSheet = new createjs.SpriteSheet({//创建精灵 framerate: 60, 'images': [loader.getResult('img')], 'frames': {'regX':0, 'height':120, 'count':6, 'regY': 0, 'width': 120}, 'animations': { 'anim': [0, 5, 'anim'], } }); img = new createjs.Sprite(spriteSheet, 'anim'); stage.addChild(img);//将img加载到舞台上 createjs.Ticker.addEventListener('tick', tick);//刷新 createjs.Ticker.setFPS(10); //每秒调用tick函数 3次 控制动画快慢 } function handleFileProgress(event){//加载中函数 console.log(loader.progress*100|0+'%'); } function tick(e){//tick函数 stage.update(event);//更新舞台 }
演示demo链接
总结:
综上所述,现在使用一个简单的表格来汇总逐帧动画常见的制作手法,希望读完本文的小伙伴们都可以在下次遇见这类动画效果时,第一时间挖掘出它背后的制作原理,好好运用这四种实现方法,(表格中所阐述的性能损耗和实现成本等仅作参考)。
上面表格看起来还是有些杂乱,还是弄一个简单的表吧,如下表所示:
四种方法各有优势和劣势。如果明确了浏览器的型号和版本支持css3时,推荐使用CSS3的方法。如果是为了广泛使用,推荐使用JavaScript的方法。当序列帧很简单的时候,不建议使用canvas来实现功能。当需要实现复杂动画或者做游戏开发的时候,使用canvas较好,可以灵活的对动画进行操作设置。
标签
关注微信号:h5-share,获取更多创意H5案例分享!也可访问H5案例分享网站www.h5anli.com,搜索查阅~
微信扫一扫
关注该公众号