首页 > 代码库 > 前端动画整合

前端动画整合

一、背景:
     合适的动画不仅更能吸引人们的眼球,也能让你的应用体验更为流畅,而将动画的效果做到极致,才能让用户感到使用你的应用是一种享受,而不是觉得生硬和枯燥。
 
二、动画技术分类:
 
     按技术类型来进行分类,分为三类:JS动画,CSS3动画,html5动画,接下来分别对三类动画进行讲解。
 
     1)JS动画
     通过一个定时器setInterval间隔来改变元素样式,动画结束时clearInterval即可。(早期类库:jquery、prototype、mootools)
     优缺点:
     优点:可控性很强,兼容性较好
     缺点:
          1、性能不佳:因为需要不断获取和修改dom布局,所以导致了大量页面重排(repaint);
          2、缺乏标准:不同的库使用了不同的API,导致即使是简单的动画也有各不相同的实现方式,调整起来比较耗时;
          3、带宽消耗:相对丰富的动画库代码量都很大,结果就是增加了http请求的大小,降低了页面的载入时间。
 
     2)css3动画
     css3两种动画实现方式:一种是transition,一种是animation,animation相比transition使用起来更为复杂。
     transition包含4种属性:transition-delay、transition-duration、transition-property、transition-timing-function,对应动画的4种属性:延迟、持续时间、对应CSS属性和缓动函数。
     transform包含7种属性:animation-name、animation-duration、animation-timing-function、animation-delay、animation-direction、animation-iteration-count、animation-fill-mode、animation-play-state,对应动画名称、持续时间、缓动函数、动画延迟、动画方向、重复次数、填充模式。
     优点:
     1、css3动画相比JS更轻量,性能更好,更易于实现。
     2、不必担心缺乏标准和增加带宽消耗的问题。
     3、不依赖于主线程,采用硬件加速(GPU)
     4、move.js是一个封装了css3动画效果的轻量级js动画库。
     
     缺点:
     1、不能动态的修改或定义动画内容
     2、不同的动画无法实现同步
     3、多个动画彼此无法堆叠
 
     示例:2-1 Transitions动画  (过渡动画)
<!DOCTYPE html>
<html>
     <head>
          <meta charset="utf-8" />
          <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>
     </head>
     <body>
          <div class="animate animate-transition">Transition Animation</div>
     </body>
</html>
 
     示例2-2:keyframes animation(关键帧动画)
<!DOCTYPE html>
<html>
     <head>
          <meta charset="utf-8" />
          <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-keyframes {
                    -webkit-animation: none;
               }
               .animate-keyframes:hover {
                    cursor: pointer;
                    -webkit-animation: frames 2s linear infinite;
               }
               @-webkit-keyframes frames {
                    0% {
                         background-color: #f00;
                         -webkit-transform: rotate(0deg);
                    }
                    100% {
                         background-color: #f00;
                         -webkit-transform: rotate(360deg);
                    }
               }
          </style>
     </head>
     <body>
          <div class="animate animate-keyframes">Transition Animation</div>
     </body>
</html>
    
     3)html5动画
     html5定义了三种绘图的方式,canvas,svg,webGL,其中svg作为一种可缩放矢量图形的实现是基于xml标签定义的,它有专门的animate标签来定义动画。而为canvas或者webGL实现动画则需要通过requestAnimationFrame(简称raf)来定期刷新画布。尽管raf的方式会让代码变得复杂,但是因为不需要那么多的文档对象(通常浏览器只需要管理一个画布),它的性能也好很多,尤其是在内存吃紧的移动端上面。
 
     3-1 svg动画:
     示例:3-1
     <!DOCTYPE html>
<html>
     <head>
          <meta charset="utf-8" />
          <style type="text/css">
               .animate-svg {
                    width: 200px;
                    margin: 0 auto;
               }
          </style>
     </head>
     <body>
          <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>
                              <animateTransform attributeName="transform" attributeType="xml" type="rotate" from="0" to="360" dur="3s" repeatCount="indefinite">SVG Animation</animateTransform>
                         </g>
                    </g>
               </svg>
          </div>
     </body>
</html>
     svn动画优缺点:
     优点:
     1) 矢量图形,不受像素影响,这个特性在不同的平台或者媒体下表现良好;
     2) SVG对动画支持较好,其DOM结构可以被其特定语法或者js控制
     3) SVG的结构是XML,其可访问性、可操作性、可编程性、可被CSS样式化完胜Canvas。另外,其支持ARIA属性
     缺点:
     1) DOM比正常的图形慢,而且如果其节点多而杂,就更慢。
     2) 不能动态修改动画内容
     3)不能与HTML内容集成,整个SVG作为一个动画
 
     3-2:requestAnimationFrame(简称raf)接口改进手段+结合js来实现高性能的动画。主要手段如下:
     优点:
     1、在每次浏览器更新页面时,能获取通知并执行应用,简单理解为RAF能在每个16.7ms间执行一次咱们的函数。
     2、最小化的消耗资源,RAF在页面被切换或浏览器最小化时,会暂停执行,等页面再次关注时,继续执行动画。
     3、在移动设备上使用3d硬件加速,最简单办法就是添加-webkit-transform: translateZ(0),原因是移动端的显卡有很强的图形渲染能力,而每个应用的webview内存却是极其有限的。
     4、js配合h5可控性好,这方面做的最全面的有Velocity.js,不过tween.js也很棒(从flash算法移植过来的,专注与动画的数值计算)。
     缺点:
     1、无法控制执行时间,执行时间由系统根据屏幕刷新时间决定
     2、浏览器兼容问题,低版本浏览器降级处理,使用setInterval或setTimeout
 
    示例3-2:requestAnimationFrame制作旋转特效
     <!DOCTYPE html>

<html>
     <head>
          <meta charset="utf-8" />
          <style type="text/css">
               .animate {
                    width: 200px;
                    height: 200px;
                    margin: 0 auto;
                    border-radius: 50%;
                   
                    line-height: 200px;
                    border-radius: 50%;
                    text-align: center;
                    color: #fff;
                    font-size: 20px;
               }
               .animate-input {
                    margin-top: 10px;
                    text-align: center;
               }
          </style>
     </head>
     <body>
          <div id="animate-RAF" class="animate animate-RAF">RAF Animation</div>
          <div class="animate-input"><input type="button" id="btn_start" value="http://www.mamicode.com/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);
               }
               // 绑定事件
               btn_start.addEventListener("click", function(event) {
                    var val = this.value;
                    if (val == "Start") {
                         frameid = requestAnimationFrame(frame);
                         this.value = "http://www.mamicode.com/Pause";
                    } else {
                         this.value = "http://www.mamicode.com/Start";
                         cancelAnimationFrame(frameid);
                    }
               }, false);
          </script>
     </body>
</html>

 
3-3:Canvas动画
优点:
1)画2D图形中,页面渲染性能比较高,页面渲染性能受图形复杂度影响小,渲染性能只受图像的分辨率的影响
2)画出来的图形可以直接保存为.png或者.jpg的图形
3)最适合于画光栅图像(如游戏和不规则集合图形等)
缺点:
1)整个一张图,没有dom节点可供操作;
2)没有实现动画的API,你必须依靠定时器和其他事件来更新Canvas
3)对文本的渲染支持是比较差
4)对要求有高可访问性(盲文、声音朗读等)页面,比较困难
 
3-4:WebGL
WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES2.0结合在一起,通过增加OpenGL ES2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型, 还能创建复杂的导航和数据视觉化。

3-5 问题思考:
 
1、不必要维护来支持多种方式实现同样的事情;
2、Web开发人员需要学习多种实现技术;
3、js不容易设置声明式动画。
4、flash动画(已慢慢过时)
      
 
三、动画基本属性
相关概念:绘制频率、屏幕刷新频率、硬件加速、60fps
 
绘制频率:页面每一帧变化都是系统绘制出来的(GPU或者CPU)。
它的最高绘制频率受限于显示器的刷新频率(而非显卡),所以大多数情况下最高的绘制频率只能是每秒60帧(frame per second,简称fps),对应于显示器的60Hz。
 
刷新频率:图像在屏幕上更新的速度,也就是屏幕上的图像每秒出现的次数,单位是Hz,刷新频率越高,屏幕上图片闪烁感就越小,稳定性也就越高。人的眼睛不容易察觉75Hz以上刷新频率带来的闪烁感。
 
硬件加速:
硬件有三个处理器:CPU、GPU和APU(声音处理器)。他们通过PCI/AGP/PCIE总线交换数据。
GPU在浮点运算、并行计算等部分计算方面,明显高于CPU的性能。
 
60Hz和60fps关系:
fps代表GPU渲染画面的频率,Hz代表显示器刷新屏幕的频率。游戏里谈到掉帧,是指GPU渲染画面频率降低。比如跌落到30fps甚至20fps,但因为视觉暂留原理,我们看到的画面仍然是运动和连贯的。
 
 
四、web Animations 1.0 通用动画模型
     web Animations API为css和svg动画提供了单一接口。旨在通过提供更好的性能、更好的控制时间线和播放、灵活、统一的JavaScript编程接口。
 
示例:4-1:点击旋转效果
 
<!DOCTYPE html>
<html>
     <head>
          <meta charset="utf-8" />
          <style type="text/css">
               .animate {
                    width: 200px;
                    height: 200px;
                    margin: 0 auto;
                    border-radius: 50%;
                   
                    line-height: 200px;
                    border-radius: 50%;
                    text-align: center;
                    color: #fff;
                    font-size: 20px;
                    cursor: pointer;
               }
               .web-animation-1 {
                    -webkit-transform: rotate(360deg);
               }
          </style>
     </head>
     <body>
          <div id="web_animation_1" class="animate web-animation-1">Web Animation-1</div>
          <script src="http://www.mamicode.com/web-animations.js"></script>
          <script type="text/javascript">
               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);
          </script>
     </body>
</html>
 
示例:4-2:更复杂时序(正负旋转)
<!DOCTYPE html>
<html>
     <head>
          <meta charset="utf-8" />
          <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;
                    cursor: pointer;
               }
               .web-animation-2 {
                    -webkit-transform: rotate(360deg);
               }
          </style>
     </head>
     <body>
          <div id="web_animation_2" class="animate web-animation-2">Web Animation-2</div>
          <script src="http://www.mamicode.com/web-animations.js"></script>
          <script type="text/javascript">
               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);
          </script>
     </body>
</html>
 
示例:4-3 并行动画
<!DOCTYPE html>
<html>
     <head>
          <meta charset="utf-8" />
          <style type="text/css">
               .web_animation_4 {
                    width: 700px;
                    margin: 0 auto;
                    padding: 10px;
                    background-color: #ccc;
                    cursor: pointer;
               }
               .web_animation_4 .par-timing-box {
                    background-color: #00f;
                    height: 20px;
                    margin: 10px;
               }
          </style>
     </head>
     <body>
          <div id="web_animation_4" class="web_animation_4">
               <div id="parItem1" class="par-timing-box" style="width: 500px;"></div>
               <div id="parItem2" class="par-timing-box" style="width: 700px;"></div>
               <div id="parItem3" class="par-timing-box" style="width: 200px;"></div>
          </div>
          <script src="http://www.mamicode.com/web-animations.js"></script>
          <script type="text/javascript">
               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);
          </script>
     </body>
</html>
 
还有很多的例子..大家可以多尝试
 
 
五、现行动画实现方案:
 
1)页面增强动画建议使用CSS动画
2)复杂动画交互建议使用RAF及setInterval或setTimeout优雅降级处理
3)业界主流动画库:
     Velocity.js是一款动画切换的jQuery插件,包含(颜色切换、转换(transform)、循环缓动、CSS切换、Scroll功能),支持Android和ios,内部使用jQuery的$.queue方法,如果能将Velocity.js依赖jQuery插件变为js原生来实现,在移动端的作用将更加明显。
4)Swipe JS 一款移动端触摸滑块幻灯片插件,不但能够使用于各种操作系统的手机,还能够利用H5的硬件加速功能来完成滑块的切换效果,其效果以及实用性非常强。
 
六、css动画比JS流畅度对比:
     根据Google Developer Chromium项目,渲染线程分为main thread和compositor thread。
     如果CSS动画只是改变transforms和opacity,这时整个CSS动画得以在compositor thread完成(而js动画则会在main thread执行,然后触发compositor进行下一步操作)
     在JS执行一些昂贵的任务时,main thread繁忙,CSS动画由于使用了compositor thread可以保持流畅。
     在主线程中,维护了一棵Layer树(LayerTreeHost),管理了TiledLayer,在compositor thread,维护了同样一颗LayerTreeHostImpl,管理了LayerImpl,这两棵树的内容是拷贝关系。因此可以彼此不干扰,当JavaScript在main thread操作LayerTreeHost的同时,compositor thread可以用LayerTreeHostImpl做渲染。当JavaScript繁忙导致主线程卡住时,合成到屏幕的过程也是流畅的。为了实现防假死,鼠标键盘消息会被首先分发到compositor thread,然后再到main thread。这样,当main thread繁忙时,compositor thread还是能够响应一部分消息,例如,鼠标滚动时,加入main thread繁忙,compositor thread也会处理滚动消息,滚动已经被提交的页面部分。
 
     CSS动画比JS流畅的前提:
     1)在Chromium基础上的浏览器中
     2)JS在执行一些昂贵的任务
     3)同时CSS动画不触发layout或paint
          在CSS动画或JS动画触发了paint或layout时,需要main thread进行Layer树的重计算,这时CSS动画或JS动画都会阻塞后续操作。
     根据CSS Triggers,只有如下属性的修改才符合“仅触发Composite,不触发layout或paint”:
     backface-visibility: 指定当元素背面朝向观察者时是否可见。
     opacity: 透明度
     perspective: 定于3D元素距视图的距离
     perspective-origin: 定义3D元素所基于的X轴和Y轴
     transform: 设置元素变形、旋转、缩放、倾斜。
 
     所以只有用上了3D加速活修改opacity时,才有机会用得上CSS动画的这一优势。
     因此,在大部分应用场景下,效率角度更值得关注还是下列问题。
     是否导致layout
     repaint的面积
     是否有高消耗的属性(css shadow等)
     是否启用硬件加速。
 
     css动画和JS动画主要的不同点是
     功能涵盖面,JS比CSS3大
     定义动画过程的@keyframes不支持递归定义,如果有多种类似的动画过程,需要调节多个参数来生成的话,将会有很大的冗余
     时间尺度上,@keyframes动画粒度粗,而JS的动画粒度控制可以很细
     CSS3动画里被支持的时间函数非常少,不够灵活
     以现有的接口,CSS3动画无法做到支持两个以上的状态转化
     实现重构难度不一,CSS3比JS更简单,性能调优方向固定
     对于帧速表现不好的低版本浏览器,CSS3可以做到自然降级,而JS则需要撰写额外代码
     css3有兼容性问题,而JS大多时候没有兼容性问题。
     
 
七、常见动画效果分类
 
     公司内部常见活动页动画库:
 
     1、modPageSlide组件:H5活动页整屏滑动切换功能,提供多种切换方式;
     2、H5FullscreenPage组件:全屏滚动效果组件
     3、iSlider:高性能H5滑屏组件
     4、css3的滑屏组件
     5、WebApp手机活动页模板
     6、ELego.js:CSS3动画流水式编程框架
     7、smartclick:移动设备HTML5点击高亮组件
    
     业界常使用的一些动画库:
     1、css3动画:move.js
     2、动画切换的jQuery插件:velocity.js
     3、移动web内容滑块类库:swipe.js
     4、提供CSS、SVG动画的单一接口:Web Animations API
     5、基于H5高性能js动画库:Collie
 
八、号称DOM动画的四大神器
     
     位移:transform: translate(npx, npx);
     缩放:transform: scale(n);
     旋转:transform: rotate(ndeg);
     透明:opacity: 0 ~ 1;

前端动画整合