转载

说说大家都熟悉的网页动画技术

前言

从古代手绘翻书动画,到胶片电影,再到多张静态图合成 gif, 这些都离不开一个术语叫

也就是我们需要绘制每一帧,然后控制一下帧与帧之间的时间间隔。

然而相邻两帧之间的变化并不大,重复绘制浪费体力, 幸亏计算机代码可以复制粘贴,然后修改一下变动的地方就可以了。

等等,好像哪里不对。

计算机代码除了可以复制粘贴,还有抽象能力。 我们可以把需要复制粘贴的代码交给计算机来重复执行。 把需要变动的地方,交给计算机来运算。

而网页中具备运算能力的只有 JS,其他的就只能是定义一下参数,剩下的就交给浏览器了。

这就是 JS 算编程,而 HTML、css 不算编程的原因。 相关讨论,回复内容+关键字 #你丫才码农#

开始

网页动画可以通过以下几种方式实现(gif、flash 除外),

作者知识面有限,如有遗漏,请留言通知我。 相关讨论,回复内容+关键字 #网页动画实现方式#

  • css3 动画
  • SVG 动画
  • JS 动画(包括 css、SVG 的属性修改实现的动画)

作者认为 canvas、webGL 只能算是一种绘图方式。 他们的动画也都是通过 JS 修改参数来实现的。 相关讨论,回复内容+关键字 #canvas动画#

最早 JS 通过 setTimeout() 或者 setInterval() 方法设置一个时间, 来控制帧与帧之间的时间间隔。

  • setTimeout() 直接用跳出来终止下一帧。
  • setInterval() 使用 clearInterval() 来取消周期执行。

但是这样效果可能不够流畅,且会占用额外的资源。 相关讨论,回复内容+关键字 #你ST设置几毫秒# 参考: http://www.cnblogs.com/chaogex/p/3960175.html?utm_source=tuicool&utm_medium=referral

后来,有了一个 requestAnimationFrame() ,让浏览器决定 最优帧速率选择绘制下一帧的最佳时机requestAnimationFrame()cancelAnimationFrame() 来结束。

所以我们来改变一下思维方式,既然帧与帧之间的时间间隔不用考虑了,那就关心一下变化速率吧。

  • Partial support refers to lacking cancelAnimationFrame support.
  • Supports webkitCancelRequestAnimationFrame rather than `webkitCancelAnimationFrame.

-- caniuse.com

好了,动画讲完了,你去找个教程看《canvas 绘图》?

别介,这才刚刚开始。

慢慢的,我们发现一些简单动画只是在修改几个 css 属性,而且只是在两三个状态之间来回变换。 大量的体力却浪费在两个状态间的补间状态函数上,而且质量良莠不齐。

来来来,这种事情就交给浏览器嘛。

css3 动画

能够执行补间状态的条件是,属性值能够转换成数值,这样就能参与运算。如:

  • 颜色(color,background-color,border-color...)
  • 长度/大小(width,height,font-size,border-width,border-radius...)
  • 透明度(opacity)
  • 堆叠顺序(z-index) 你吖补间它有毛用

而不能参与运算就意味着不能拿来补间状态,也就是没有中间状态,如:

  • position(absolute、fixed、relative...)
  • background-image(一个确定的 url)
  • ...

一拍脑门就能想到,创建一个补间动画的条件有:

  • 开始状态
  • 结束状态
  • 执行时间
  • 补间效果

假如有个方块,宽度从 10px 变成 100px。

开始状态呢,在原 css 里就可以定义了 width: 10px

结束状态呢,我们可以通过用 JS 直接修改 width 值,或者增加一个 class 选择器的方式, 或者是 :hover 等其他表示状态的伪类,让 width: 100px

而这时,你需要一个补间动画属性来声明 执行时间补间效果 , 它就是 transition ,中文译作 过渡 ,就是我所说的补间的意思。

transition 为以下属性的简写

  • transition-property 规定哪个属性应用过渡
  • transition-duration 执行时间
  • transition-timing-function 补间效果,默认为 ease
  • transition-delay 延迟多少时间开始

参考: http://w3school.com.cn/css3/css3_transition.asp

Support listed is for transition properties as well as the transitionend event. The prefixed name in WebKit browsers is webkitTransitionEnd

-- caniuse.com

css3 还提供了一个 animation 属性来创建更丰富的自定义动画,而减少 JS 的介入。

比如:

  • 你想一个动画中拥有多个状态
  • 每个状态修改的属性值较多
  • 循环播放
  • 逆向播放
  • 可自动开始,可中途暂停

animation@keyframes 配合使用。

@keyframes 用来定义动画, animation 则可以多处应用,他们通过一个 name 来连接彼此, 因此 @keyframes 必须要起个名字,而 animation 则有个 animation-name

animation 在应用时,你可以自定义它:

  • animation-duration 执行时间
  • animation-time-function 补间效果,默认是 ease
  • animation-delay 延迟多少时间开始
  • animation-iteration-count 循环播放次数
  • animation-direction 是否在下一周期逆向播放
  • animation-play-state 动画是否暂停,通过它,可以实现是否自动播放。要中途暂停的话,就要修改值,通过伪类或 JS 实现
  • animation-fill-mode 这个属性倒是有点出乎意料之外,请自行研究使用场景

可见 w3c 规范制定者们考虑到我们要用起来简单呢,基本上和我们思维方式一致。

实现动画的多个状态是在 @keyframes 定义时完成的。

采用 0%~100% 的分割方式,我们就不用在 执行时间 之外考虑时间问题了。

参考: http://w3school.com.cn/css3/css3_animation.asp

Partial support in Android browser refers to buggy behavior in different scenarios.

--caniuse.com

SVG 动画

css3 动画属性只管得住自己的 css 属性,SVG 绘制的图形,还得 SVG 自己解决。而对于 SVG 的 css 样式,一般两种皆可。

SVG 大大们的思维方式就有点绕了,竟然提供了 5 种动画 标签让我选择:

  • set 相当于 animate 的 calcMode="discrete",忽略
  • animate
  • animateColor 相当于 animate 的 attributeName="color",忽略
  • animateTransform
  • animateMotion

我们先来看看和 css3 最像的 animate 标签,拥有的属性有

  • attributeName 规定哪个属性应用过渡
  • from 开始状态
  • to/by 结束状态,至少出现一个
  • values 多个状态时,忽略 from/to/by
  • begin 延迟多少时间开始
  • dur 执行时间
  • calcMode,keyTimes,keySplines 自定义补间效果
  • repeatCount,repeatDur 循环播放次数/持续时间
  • ...

额,大概就是这样,下一个吧。

animateTransform 主要是为了 attributeName="transform" , 跟 css3 动画结合 transform 变换类似,多了一个 type="scale" 属性用来区分相关参数。

animateMotion 是 SVG 甩 css3 动画一条街的强大技能,可以让SVG各种图形沿着特定的 path 路径运动。

SVG 动画比 css 动画更强大,所以也更复杂。

细分成这 5 类标签,大概是性能考虑,人工简单区分一下数值、颜色、变换,可以为计算机省去大量的无用运算。

作者在这里也没办法讲的更详细,估计你也没看太明白 建议阅读: http://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/

JS 还有啥用

通过声明属性,调用浏览器来实现的方式,毕竟有限,JS 可以为我们提供无限可能。

通过对比 CSS3 和 SVG 我们也能看出来,要实现的东西越多,我们需要区分、记忆的属性也越多。 一个复杂动画使用声明属性的方式有可能并没有通过编写逻辑来得更爽。看,SVG.js。

在这里倒是想到了 Grunt 和 Gulp 之争 相关讨论,请回复+关键字 #不要给我太多配置项#

css3 属性中声明的补间效果实在有限,SVG 的 calcMode,keyTimes,keySplines 又略显复杂,

于是 github 上出现了一大批补间效果仓库,更有强大者弥补了 CSS3 与 SVG 动画上各个方面的不足。

https://github.com/bendc/animateplus

  • 简单小巧,使用简单
  • 4 大类/29 种补间动画效果
  • 支持 SVG path 路径的补间过渡
    • !稍微有点鸡肋,path 长度不一致或类型不同时出现动画混乱
  • !仅支持开始、结束两个状态

    animate({     el: "div",  // 选择器     duration: 1000, // 执行时间     delay: 0,   // 延迟多少时间开始     easing: "easeOutElastic",   // 补间效果     loop: false,    // 是否循环     direction: normal,  // 是否重复     begin: function () {},  // 开始事件     complete: function () {},   // 结束事件     ...: ['', '']   // css/SVG 需要改变的属性 }); 

http://mojs.io/tutorials/easing/path-easing/

无论你定义多少补间效果,都满足不了所有人的需求,这里有个 path 路径补间函数生成器。 var myFunc = mojs.easing.path(path) ,输入一个 SVG path,myFunc() 就是你自己的补间函数。

https://github.com/mbostock/d3/wiki/%E8%BF%87%E6%B8%A1

  • 太屌,不进行反面评论
  • 最喜欢它的链式操作

    var svg = d3.select("#a")   // 选择器     .attr('d', svg_num_path_d[0])     // ... 可以进行其他设置     .attr('fill', '#f00')   // 设置初始状态     .transition()   // 返回 transition 对象     .call(function (transition) {         return transition   // 承接 transition 对象             .duration(3000) // 执行时间             .delay(0)   // 延迟多少时间开始             .ease('cubic-in-out')   // 补间效果             .attr('fill', '#ff0');  // 本次过渡结束状态     })  // 重新返回选择器对象     // ... 可以进行其他设置     .transition()   // 进行下一个过渡     .call(function (transition) {         return transition.duration(3000).attr('fill', '#f0f');     })     // ... 可以进行其他设置     ; 

作者将会在这里对比更多 JS 动画函数库的使用方法

鸣谢

正文到此结束
Loading...