相关概念:绘制频率、屏幕刷新频率、硬件加速、60fpsjavascript
绘制频率:css
页面上每一帧变化都是系统绘制出来的(GPU或者CPU)【参考浏览器渲染原理】。但这种绘制又和PC游戏的绘制不一样,它的最高绘制频率受限于显示器的刷新频率(而非显卡),因此大多数状况下最高的绘制频率只能是每秒60帧(frame per second,如下用fps简称),对应于显示器的60Hz。60fps是一个最理想的状态,在平常对页面性能的测试中,60fps也是一个重要的指标,the closer the better。html
刷新频率:java
图像在屏幕上更新的速度,也即屏幕上的图像每秒钟出现的次数,它的单位是赫兹(Hz)。刷新频率越高,屏幕上图像闪烁感就越小,稳定性也就越高,换言之对视力的保护也越好。通常人的眼睛、不容易察觉75Hz以上刷新频率带来的闪烁感,所以最好能将您显示卡刷新频率调到75Hz以上。要注意的是,并非全部的显示卡都可以在最大分辨率下达到70Hz以上的刷新频率(这个性能取决于显示卡上RAMDAC的速度),并且显示器也可能由于带宽不够而不能达到要求。影响刷新率最主要的仍是显示器的带宽。jquery
显示器带宽是显示器视频放大器通频带宽度的简称,指电子枪每秒钟在屏幕上扫过的最大总像素数,以MHz(兆赫兹)为单位。 带宽的值越大,显示器性能越好。git
硬件加速:github
硬件有三个处理器,CPU、GPU和APU(不是加速处理器是声音处理器)。他们经过PCI/AGP/PCIE总线交换数据。今天,GPU已经再也不局限于3D图形处理了,GPU通用计算技术发展已经引发业界很多的关注,事实也证实在浮点运算、并行计算等部分计算方面,GPU能够提供数十倍乃至于上百倍于CPU的性能。web
60Hz和60fps是什么关系编程
没有任何关系。fps表明GPU渲染画面的频率,Hz表明显示器刷新屏幕的频率。一幅静态图片,你能够说这副图片的fps是0帧/秒,但绝对不能说此时屏幕的刷新率是0Hz,也就是说刷新率不随图像内容的变化而变化。游戏也好浏览器也好,咱们谈到掉帧,是指GPU渲染画面频率下降。好比跌落到30fps甚至20fps,但由于视觉暂留原理,咱们看到的画面仍然是运动和连贯的。canvas
_PS: 如下示例在Chrome环境中运行_
实例:
<style type="text/css"> .animate { width: 200px; height: 200px; margin: 0 auto; border-radius: 50%; background-color: #f00; line-height: 200px; border-radius: 50%; text-align: center; color: #fff; font-size: 20px; } .animate-transition { transition : transform 2s linear; -moz-transition : -moz-transform 2s linear; -webkit-transition : -webkit-transform 2s linear; -o-transition : -o-transform 2s linear; } .animate-transition:hover { cursor: pointer; transform : rotate(360deg); -moz-transform : rotate(360deg); -webkit-transform : rotate(360deg); -o-transform : rotate(360deg); } </style> <div class="animate animate-transition">Transition Animation</div>
Keyframes animation经过定义多个关键帧以及定义每一个关键帧中的元素的属性值来实现更为复杂的动画效果。
实例:
<style type="text/css"> .animate-keyframes { -webkit-animation: frames 2s linear infinite; } .animate-keyframes:hover { cursor: pointer; -webkit-animation: none; } @-webkit-keyframes frames { 0% { background-color: #f00; -webkit-transform: rotate(0deg); } 100% { background-color: #f00; -webkit-transform: rotate(360deg); } } </style> <div class="animate animate-keyframes">keyframes animation</div>
优势:
简单、高效
声明式的
不依赖与主线程,采用硬件加速(GPU)
简单的控制keyframe animation 播放和暂停
缺点:
不能动态的修改或定义动画内容
不一样的动画没法实现同步
多个动画彼此没法堆叠
另:
1) CSS3 transition强制硬件加速会加大GPU消耗,高负荷情形下将致使运行不流畅。这种状况在移动设备上尤其明显。(特殊状况下,好比当数据在浏览器主线程和排版线程之间传递产生的瓶颈也会致使不流畅)。某些CSS属性,好比transform和opacity,则不受这些瓶颈影响。Adobe在这里精心总结了这些问题。详细请戳
transition的兼容性问题是个诟病,IE10+及现代浏览器,使用起来会形成不少不便。
因为transition并非由JavaScript原生控制(而仅仅是由JavaScript触发),浏览器没法获知如何与控制这些transition的JavaScript代码同步地优化他们。
2) keyframes animation 的动画曲线会应用到全部变化的属性上,并且手写比较复杂的动画,写起来就是噩梦。
<div class="animate-svg"> <svg id="svgAnimation" ns="http://www.w3.org/2000/svg" version="1.1" width="200" height="200"> <g transform="translate(100,100)"> <g> <rect width="200" height="200" rx="100" ry="100" fill="red" transform="translate(-100,-100)"></rect> <text x="-60" y="-0" font-size="20" fill="white" >SVG Animation</text> <!-- Add ease-in-out and infinite iterations to this animation and the code --> <animateTransform attributeName="transform" attributeType="xml" type="rotate" from="0" to="360" dur="3s" repeatCount="indefinite">SVG Animation</animateTransform> </g> </g> </svg> </div>
优势:
1) 矢量图形,不受像素影响——SVG的这个特性使得它在不一样的平台或者媒体下表现良好,不管屏幕分辨率如何
2) SVG对动画的支持较好,其DOM结构能够被其特定语法或者Javascript控制,从而轻松的实现动画
3) Javascript能够彻底控制SVG Dom 元素
4) SVG的结构是XML,其可访问性(盲文、声音朗读等)、可操做性、可编程性、可被CSS样式化完胜Canvas。另外,其支持 ARIA 属性,使其如虎添翼。
缺点:
1) DOM比正常的图形慢,并且若是其结点多而杂,就更慢。
2) SVG 画点报表什么的,还行;在网页游戏前,就一筹莫展了;固然能够结合 Canvas + SVG实现。
3) 不能动态的修改动画内容
4) 不能与HTML内容集成
5) 整个SVG做为一个动画
6) 浏览器兼容性问题,IE8-以及Android 2.3默认浏览器是不支持SVG
jQuery动画使用setInterval实现:
// 用例 $("#div").animate({}); // 源码 jQuery.fx.timer = function( timer ) { if ( timer() && jQuery.timers.push( timer ) && !timerId ) { timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); } }; jQuery.fx.interval = 13;
How to determine the best “framerate” (setInterval delay) to use in a JavaScript animation loop?
优势:
易用,低效,兼容好;
缺点:
1) setInterval多个间隔可能会被跳过
2) setInterval多个间隔可能比预期小
3) 不一样浏览器的精度量级不一样:
4) jQuery 没法解决频繁触发 Layout 致使的抽动。
实例:
<style type="text/css"> .animate-RAF { } .animate-input { margin-top: 10px; text-align: center; } </style> <div id="animate-RAF" class="animate animate-RAF">RAF Animation</div> <div class="animate-input"><input type="button" id="btn_start" value="Start" style="width:100px;height:30px"></div> <script type="text/javascript"> var animate_raf = document.getElementById("animate-RAF"), btn_start = document.getElementById("btn_start"), frameid = null; function frame(time) { animate_raf.style['-webkit-transform'] = 'rotate('+ Math.cos(time/1000)*360 +'deg)'; frameid = requestAnimationFrame(frame); } // bind Event btn_start.addEventListener("click", function(event) { var val = this.value; if(val === "Start") { frameid = requestAnimationFrame(frame); this.value = "Pause"; }else { this.value = "Start"; cancelAnimationFrame(frameid); } }, false); </script>
优势:
1) 在每次浏览器更新页面时,能获取通知并执行应用。 简单理解为,RAF能在每一个16.7ms间执行一次我们的函数,很少很多。
2) 最小化的消耗资源,RAF在页面被切换或浏览器最小化时,会暂停执行,等页面再次关注时,继续执行动画。
3) 相比 CSS 动画有更好的掌控,能合理下降CPU的使用。
缺点:
1) 没法控制执行时间,执行时间由系统根据屏幕刷新时间决定
2) 浏览器兼容性问题,IE10+及现代浏览器,低版本浏览器建议降级处理,使用setInterval或setTimeout
优势:
1) 画2D图形时,页面渲染性能比较高
2) 页面渲染性能受图形复杂度影响小
3) 渲染性能只受图形的分辨率的影响
4) 画出来的图形能够直接保存为 .png 或者 .jpg的图形
5) 最适合于画光栅图像(如游戏和不规则几何图形等),编辑图片还有其余基于像素的图形操做。
缺点:
1) 整个就是一张图,不管你往上画什么东西——没有DOM 结点可供操做
2) 没有实现动画的API,你必须依靠定时器和其余事件来更新Canvas
3) 对文本的渲染支持是比较差
4) 对要求有高可访问性(盲文、声音朗读等)页面,比较困难
5) 对交互要求高的(好比TIBCO的不少产品)的界面,不建议使用Canvas
WebGL是一种3D绘图标准,这种绘图技术标准容许把JavaScript和OpenGL ES 2.0结合在一块儿,经过增长OpenGL ES 2.0的一个JavaScript绑定,WebGL能够为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就能够借助系统显卡来在浏览器里更流畅地展现3D场景和模型了,还能建立复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于建立具备复杂3D结构的网站页面,甚至能够用来设计3D网页游戏等等。
浏览器支持:
Internet Explorer 11+
Google Chrome 9+
Firefox 4+
Opera 12+
Safari 5.1+
1) 不一样的api有不一样的模型动画
2) 没必要要的维护来支持多种方式实现一样的事情
3) Web开发人员须要学习多种实现技术
4) Javascript不容易设置声明式动画
2) JavaScript implementation of the Web Animations API
Web Animations API为CSS和SVG动画提供了单一接口。旨在经过提供更好的性能、更好的控制时间线和播放、灵活、统一的Javascript编程接口,使作一些事情更容易。
当前状态:
Specification at First Public Working Draft: www.w3.org/TR/web-animations
Chrome:
CSS Transitions & Animations rewritten on top of the Web Animations model
JavaScript API in development behind a flag
Firefox & Safari: Started implementation
IE: No public signals
实例一:A simple example
var web_animation_1 = document.getElementById("web_animation_1"); web_animation_1.addEventListener('click', function() { web_animation_1.animate([{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],{ duration: 2 }); }, false);
实例二:More complex timing
var web_animation_2 = document.getElementById("web_animation_2"); web_animation_2.addEventListener('click', function() { web_animation_2.animate([{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],{ direction: 'alternate', duration: 1, iterations: Infinity, easing: 'ease-in-out', playbackRate: 2 }); }, false);
实例三:Without the syntactic sugar
var web_animation_3 = document.getElementById("web_animation_3"); web_animation_3.addEventListener('click', function() { var obj = new Animation(web_animation_3,[{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],{ duration: 2 }); document.timeline.play(obj); }, false);
实例四:Parallel animation grouping
var web_animation_4 = document.getElementById("web_animation_4"), parItem1 = document.getElementById("parItem1"), parItem2 = document.getElementById("parItem2"), parItem3 = document.getElementById("parItem3"); web_animation_4.addEventListener('click', function() { var obj = new ParGroup([ new Animation(parItem1, [{width: '0px'}, {width: '500px'}], 1), new Animation(parItem2, [{width: '0px'}, {width: '700px'}], 1), new Animation(parItem3, [{width: '0px'}, {width: '200px'}], 1), ]) document.timeline.play(obj); }, false);
实例五:Sequential animation grouping
var web_animation_5 = document.getElementById("web_animation_5"), seqItem1 = document.getElementById("seqItem1"), seqItem2 = document.getElementById("seqItem2"), seqItem3 = document.getElementById("seqItem3"); web_animation_5.addEventListener('click', function() { var obj = new SeqGroup([ new Animation(seqItem1, [{width: '0px'}, {width: '200px'}], 1), new Animation(seqItem2, [{width: '0px'}, {width: '300px'}], 1), new Animation(seqItem3, [{width: '0px'}, {width: '200px'}], 1), ]) document.timeline.play(obj); }, false);
实例六:Nested grouped animations
var web_animation_6 = document.getElementById("web_animation_6"), outerSeqItem1 = document.getElementById("outerSeqItem1"), outerSeqItem2 = document.getElementById("outerSeqItem2"), innerParItem1 = document.getElementById("innerParItem1"), innerParItem2 = document.getElementById("innerParItem2"), innerParItem3 = document.getElementById("innerParItem3"); web_animation_6.addEventListener('click', function() { var parobj = new ParGroup([ new Animation(innerParItem1, [{width: '0px'}, {width: '300px'}], 1), new Animation(innerParItem2, [{width: '0px'}, {width: '300px'}], 1), new Animation(innerParItem3, [{width: '0px'}, {width: '300px'}], 1), ]); var seqobj = new SeqGroup([ new Animation(outerSeqItem1, [{width: '0px'}, {width: '200px'}], 1), parobj, new Animation(outerSeqItem2, [{width: '0px'}, {width: '200px'}], 1), ]); document.timeline.play(seqobj); }, false);
实例七:Path animations
var web_animation_7 = document.getElementById("web_animation_7"); web_animation_7.addEventListener('click', function() { var obj = new Animation(web_animation_7, new PathAnimationEffect( 'M 100 200 ' + 'C 200 100 300 0 400 100 ' + 'C 500 200 600 300 700 200 ' + 'C 800 100 900 100 900 100', 'auto-rotate'), { duration: 2, direction: 'alternate', easing: 'ease-in-out', iterations: Infinity, }); document.timeline.play(obj); }, false);
实例八:Custom animation effects
function customAnimationEffect(timeFraction, iteration, target) { web_animation_8.innerHTML = 'timeFraction: ' + timeFraction.toFixed(2) + '\n' + 'iteration: ' + iteration; } var web_animation_8 = document.getElementById("web_animation_8"); var obj = new Animation(null, {sample: customAnimationEffect}, { duration: 2, direction: 'alternate', easing: 'ease-in-out', iterations: Infinity, }); var customPlayer = document.timeline.play(obj); window.addEventListener('slideenter', function(event) { if (event.slide == customSlide) { customPlayer.currentTime = 0; } }, false);
实例九:综合实例
(function(document) { 'use strict'; var Animations = {}, player, controls = document.getElementById('animate-controls'); Animations.targets = { path: document.getElementById('path'), ballContainer: document.getElementById('animate-ball-container'), ball: document.getElementById('animate-ball') }; Animations.keyframeMove = new Animation(Animations.targets.ballContainer, [{ offset: 0, transform: 'translate(0,0)' }, { offset: 1, transform: 'translate(600,0)' }], { duration: 2000 }); Animations.keyframeSpinRoll = new Animation(Animations.targets.ball, [{ transform: 'rotate(950deg)' }], { duration: 2000 }); Animations.motionpathBounce = new Animation(Animations.targets.ballContainer, new MotionPathEffect("M25,25 " + "a150,100 0 0,1 300,0 " + "a75,50 0 0,1 150,0 " + "a35,20 0 0,1 70,0 " + "a2,1 0 0,1 35,0 " + "h45"), { duration: 2500 }); Animations.keyframeSpinBounce = new Animation(Animations.targets.ball, [{ transform: 'rotate(950deg)' }], { duration: 2500 }); Animations.animationGroupRoll = new AnimationGroup([Animations.keyframeMove, Animations.keyframeSpinRoll], { easing: 'ease-out' }); Animations.animationGroupBounce = new AnimationGroup([Animations.motionpathBounce, Animations.keyframeSpinBounce], { easing: 'ease-out' }); controls.addEventListener('click', function(event) { if (event.target) { var targetElement = event.target; switch (targetElement.id) { case 'keyframe-start': player = document.timeline.play(Animations.animationGroupRoll); break; case 'motionpath-start': player = document.timeline.play(Animations.animationGroupBounce); break; case 'pause': player.pause(); break; case 'cancel': player.cancel(); break; case 'play': player.play(); break; case 'reverse': player.reverse() } } }) })(document);
1) 页面加强动画建议使用CSS动画
2) 复杂动画交互建议使用RAF及setInterval 或setTimeout优雅降级处理
(function() { var lastTime = 0, vendors = ['webkit', 'moz']; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(), timeToCall = Math.max(0, 16.6 - (currTime - lastTime) ), id = window.setTimeout(function() { callback(currTime + timeToCall); },timeToCall); lastTime = currTime + timeToCall; return id; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function(id) { clearTimeout(id); }; } })();
3) 推荐动画库Velocity.js、GreenSock:
1) Velocity.js是一款动画切换的jQuery插件,它从新实现了jQuery的$.animate()方法从而加快动画切换的速度。Velocity.js只有7k的大小,它不只包含了$.animate()的全部功能,而且还包含了颜色切换、转换(transform)、循环、缓动、CSS切换、Scroll功能,它是jQuery、 jQuery UI、CSS变换 在动画方面的最佳组合。
Velocity.js支持IE8+、Chrome、Firefox等浏览器,并支持Andriod以及IOS。
Velocity.js在内部实现中使用了jQuery的$.queue()方法,所以它比 jQuery的$.animate()、$.fade()、$.delay()方法更加流畅,其性能也高于CSS的animation属性。
2) GreenSock:GSAP v12平台
很是快的速度:性能是很是重要的,尤为是在移动设备上。GSAP不断优化,以保证互动项目的快速响应、高效率及平滑,你能够从这里查看动画效果测试。
异想天开的强劲:内置众多引擎的功能,如动画色彩、贝塞尔曲线、CSS样式属性、Flash滤镜、数组等等,定义不一样的回调,能够经过帧或者秒定义运动。
兼容性:Flash,HTML5,jQuery,Canvas,CSS,新浏览器,旧浏览器,RequireJS,EaseIJS,移动设备等等-GSAP均可以很好的与他们兼容,你能够选择你熟悉的工具来使用。
Javascript,AS3/AS2:选择适合你的语言来完成动画。
轻量与可扩展性:模块化与插件式的结构保持了核心引擎的轻量,TweenLite包很是小(基本上低于7kb)。
没有依赖:GSAP没有基于第三方工具来构建(虽然它将jQuery做为选择器),所以能保证最短的加载时间与最大化性能。
高等序列:不用受限于线性序列,能够重叠动画序列,你能够经过精确时间控制,灵活地使用最少的代码实现动画。
良好的技术支持:能够经过论坛反馈,会有专家和资深活跃用户回答问题。
任何对象均可以实现动画:是的,任何,不用预约义的属性,任何对象的任意数字属性均可以实现动画,若是这些属性(如颜色,滤镜,非数值属性等)须要处理,插件能够实现。若是没有,咱们能够实现一个。
重写管理:GSAP帮助防止动画引擎的冲突以及高级选项的设置。
易于学习:文档、教程、 示例、学习指南、论坛,还有不少学习资源,很是地丰富。
许可证:除商业用途意外,GSAP彻底免费。
CSS Will Change Module Level 1
CSS Will Change Module Level 1 (中文版本)
CSS vs. JS Animation: Which is Faster?
CSS animations and transitions performance: looking inside the browser
SVG or Canvas? СHoosing Between the Two
Exploring the Web Animations API
Everything You Need to Know About the CSS will-change Property
The (80-storey) Elevator Pitch