浅谈前端实现动画效果的一些方式(包括但不限于)。

以下内容是我16年3月份在公司做内部分享时的一些内容,虽然时间有点远,但是我觉得还是比较适用的。

1. Flash,很久以前都会使用的一个方式,在十年以前甚至有很多用纯flash做的网站,我自己还做过一个,还是比较有意思的。到了中期,用flash来做动画效果后再引到html内,在html5 video之前也基本用flash的音视频播放器。现在基本已经弃用。

  • 功能强大:动画、视频、播放器、特效等。
  • 有flash的脚本语言ActionScript,简称AS。能做网页、能做事件交互、能够完成js做不了的BOM操作和本地操作等
  • 移动端不兼容
  • 过时-adobe已放弃-正式停止更新

2. GIF图片
gif.gif

  • 兼容性最好
  • 画质差,PNG有毛边
  • 无交互、图片大
  • 前端人员不太擅长制作

3.javascript 定时器动画 setInterval setTimeout

定时器:实现上就是通过一个定时器setInterval 每隔一定时间来改变元素的样式,动画结束时clearInterval即可。早期的类库包括 jquery、prototype等等都是这种方式。在CSS3之前,最初的前端动画大多都是JS来实现。

  • 使用简单,可以交互,可控性很强,兼容好
  • 性能不佳,因为需要不断获取和修改Dom的布局,所以导致了大量页面重绘
  • 缺乏标准,不同的库使用了不同的API,导致即使是简单的动画也有各不相同的实现方式
  • 复杂和长时间的定时器在移动端效果不稳定
  • 定时器不靠谱:setInterval多个间隔可能会被跳过,setInterval多个间隔可能比预期小,不同浏览器的精度不同

4. css3动画
transition过渡:顾名思议,可以实现一些简单的不需要太多的控制与步骤的过渡动画。

animation动画:与transition不同的是,animation属性可以像FLASH制作动画一样,通过关键帧控制动画的每一步,实现更为复杂的效果。并且功能更强大。

css3动画相比与JS动画更轻量,性能更好,更易于实现。animation相比 transtion 使用起来更为复杂,但也提供了更多的控制。

css3动画缺点:不同的动画无法实现同步,多个动画彼此无法堆叠,复杂的动画编辑麻烦,低版本兼容性不好。

关于CSS3动画,网上案例太多,就不细说了。

5.SVG实现动画
svg动画能够实现的:

  • 动画元素的数值属性(X, Y, …)
  • 动画属性变换(平移或旋转)
  • 动画颜色属性
  • 沿着运动路径运动

前面的三条CSS3都是可以有所担当的,最后这一条,呵呵。

示例1:

<svg width="120" height="420" >
    <rect x="10" y="10" width="100" height="100">
        <animate attributeType="XML"
                 attributeName="y"
                 from="-100" to="120"
                 dur="5s"
                 repeatCount="1"
                 fill="remove"/>
    </rect>
</svg>

attributeType:CSS|XML|auto,变化的是属性还是CSS还是自动匹配,可以省
attributeName:要变化的元素属性名称,也可以是CSS名称
from:开始值
to:结束值
repeatCount:表示动画执行次数,可以是合法数值或者无限“indefinite”
dur:动画时间,常见单位有 "h"|"min"|"s"|"ms"
fill:表示动画结束状态。支持参数有:freeze | remove. 其中remove是默认值,表示动画结束直接回到开始的地方。freeze“冻结”表示动画元素保持了动画结束之后的状态。
不写form to的情况下,可以写values="300;200;300"

示例2:多个变化一起

<svg width="800" height="300" >
 <g transform="translate(100,100)" >
    <text id="TextElement" x="0" y="0"
          font-family="Verdana" font-size="35.27" visibility="hidden"  >
      It's alive!
      <set attributeName="visibility" attributeType="CSS" to="visible"
           begin="1s" dur="6s" fill="freeze" />
      <animateMotion path="M 0 0 L 100 100"
           begin="1s" dur="6s" fill="freeze" />
      <animate attributeName="fill" attributeType="CSS"
           from="rgb(0,0,255)" to="rgb(128,0,0)"
           begin="1s" dur="6s" fill="freeze" />
      <animateTransform attributeName="transform" attributeType="XML"
           type="rotate" from="-30" to="0"
           begin="1s" dur="6s" fill="freeze" />
      <animateTransform attributeName="transform" attributeType="XML"
           type="scale" from="1" to="3" additive="sum"
           begin="1s" dur="6s" fill="freeze" />
    </text>
  </g>
</svg>

set:是animate的简化,主要用来改变非数值属性的属性值。
begin:延时开始
animateMotion:沿某运动路线移动SVG元素。
additive控制动画是否附加。支持参数有:replace | sum. 默认值是replace.

示例3:延着某一路径

<body>


<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
  <text font-family="microsoft yahei" font-size="40" x="0" y="0" fill="#cd0000">马
    <animateMotion path="M10,80 q100,120 120,20 q140,-50 160,0" begin="0s" dur="3s" repeatCount="indefinite"/>
  </text>
  <path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
</svg>

<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
  <text font-family="microsoft yahei" font-size="40" x="0" y="0" fill="#cd0000">马
    <animateMotion path="M10,80 q100,120 120,20 q140,-50 160,0" begin="0s" dur="3s" rotate="auto" repeatCount="indefinite"/>
  </text>
  <path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
</svg>


<svg width="5cm" height="3cm"  viewBox="0 0 500 300">
  <path id="path1" d="M100,250 C 100,50 400,50 400,250"
        fill="none" stroke="blue" stroke-width="7.06"  />
  <circle cx="100" cy="250" r="17.64" fill="blue"  />
  <circle cx="250" cy="100" r="17.64" fill="blue"  />
  <circle cx="400" cy="250" r="17.64" fill="blue"  />

  <path d="M-25,-12.5 L25,-12.5 L 0,-87.5 z" fill="yellow" stroke="red" stroke-width="7.06"  >
    <animateMotion dur="6s" repeatCount="indefinite" rotate="auto" >
       <mpath xlink:href="#path1"/>
    </animateMotion>
  </path>
</svg>
</body>

通过将 rotate="auto" ,用来控制是否自动旋转

示例4:SVG结合CSS3做点有意思的事情:

<style>
* {
     margin: 0;
     padding: 0;
}
path {
  stroke-dasharray:44;animation: dash 5s linear infinite;
}
@keyframes dash {
  to {
    stroke-dashoffset: 1000;
  }
}
</style>
</head>
<body>
<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
  <path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
</svg>
</body>

<style>
* {
     margin: 0;
     padding: 0;
}
path {
   stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: dash 5s linear infinite;
}
@keyframes dash {
  to {
    stroke-dashoffset: 0;
  }
}
</style>
</head>
<body>
<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
  <path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
</svg>
</body>

svg动画总结

  • svg可以实现比DIV更复杂的图形,所以也可以实现更复杂的动画
  • svg DOM结构可以被其特定语法(animate)或者Javascript控制,从而轻松的实现动画
  • 整个SVG作为一个动画,并且动画复杂编辑麻烦
  • 效率不高,而且如果其结构多而杂,就更慢
  • 浏览器兼容性不好,IE8-以及Android 2.3以下是不支持SVG,移动端未测

html5 的canvas、webgl,只是增加了绘画方式的选择,与动画的怎么变化无关,没有实现动画的API,你必须依靠定时器和其他事件来更新画布。所以与本次说的主题动画无关。但是html5也提供了一个新的动画接口....

6.RAF
性能更好的js动画实现方式——requestAnimationFrame。

前面说过,JS定时器有着严重的性能问题,虽然某些现代浏览器对这两函个数进行了一些优化,但还是无法跟css3的动画性能相提并论。但是css3动画还是有不少局限性,比如不是所有属性都能参与动画、动画缓动效果太少、无法完全控制动画过程等等。这个时候,就该requestAnimationFrame出马了。

这专门为实现高性能的帧动画而设计的一个API,目前已在多个浏览器得到了支持,包括IE10+,Firefox,Chrome,Safari,Opera等,在移动设备上,ios6以上版本以及IE mobile 10以上也支持requestAnimationFrame,唯一比较遗憾的是目前低版本安卓上并不支持,不过未来全面支持这已经是大势所趋。


<body>
<div id="box" style="width:1px;height:100px; background:red"></div>
<script>
var oBox=document.getElementById('box');
var w=1,id;
function render(t){    
    console.log(t);//返回的间隔时间
    w++;
    oBox.style.width=w+'px';
    if(w<500)id=requestAnimationFrame( render );
    console.log(id);
};
id=requestAnimationFrame( render );
oBox.onclick=function(){
    cancelAnimationFrame(id);    //通过id停止
};

</script>

</body>

是不是看起来很简单就可以实现。

  • requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率约为每秒60帧(每帧约16MS)。
  • 如果页面不是激活状态下或在隐藏或不可见的元素中,将不会进行重绘,这当然就意味动画会自动暂停,有效节省了cpu和内存使用量。
  • 原理其实也就跟定时器差不多,通过递归调用同一方法来不断更新画面以达到动起来的效果,但它优于定时器的地方在于它是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用。
  • 所以,可以这么说,requestAnimationFrame就是一个性能优化版、专为动画量身打造的setTimeout,不同的是requestAnimationFrame不是自己指定回调函数运行的时间。
  • 在前几年各个支持requestAnimationFrame的浏览器有些还是自己的私有实现,所以必须加前缀,对于不支持requestAnimationFrame的浏览器,我们只能使用setTimeout,因为两者的使用方式几近相同,所以这两者的兼容并不难。对于支持requestAnimationFrame的浏览器,我们使用requestAnimationFrame,而不支持的我们优雅降级使用传统的setTimeout。把它们封装一下,就能得到一个统一兼容各大浏览器的API了。

*总结:
无论何种需求,首选RAF
轻量级简单动画用css3
复杂动画效果CSS3不能满足的情况下用JS定时器
以上都无法满足的情况下还是网上找相应的动画库吧(js库、css3库、svg动画库)*

附:简单封装RAF:requestAnimationFrame


andy
6 声望3 粉丝

贪财好色!经不住诱惑!