网络动画曾经是 JavaScript 的产物,但随着世界转向移动设备,动画已迁移到 CSS,以遵循声明式语法,以及浏览器能够利用它进行的优化。在移动设备上,60fps 的帧速率始终是您的目标,因此,无论浏览器如何高效显示内容,都不在意这件事。
越来越多的工具可以提高 JavaScript 驱动的动画的效率,但终极目标是将声明式动画和命令式动画统一起来。在这种情况下,如何编写动画的决定取决于最明确的代码,而不是一种形式(而非另一种形式)可以实现什么。
Web Animations 会回应这一调用,其第一部分以 element.animate()
的形式传送到 Chrome 36 中。借助这个新功能,您可以只使用 JavaScript 制作动画,并且能够像任何 CSS 动画或过渡效果一样高效运行(事实上,从 Chrome 34 开始,所有这些方法的驱动方式都是完全相同的 Web Animations 引擎)。
语法很简单,如果您曾经编写过 CSS 过渡或动画,应该对它的各个部分十分熟悉:
element.animate([
{cssProperty: value0},
{cssProperty: value1},
{cssProperty: value2},
//...
], {
duration: timeInMs,
iterations: iterationCount,
delay: delayValue
});
这个新功能的最大优势是消除了许多尴尬的现实问题,让动画可以流畅、不卡顿。
例如,对于去年的追踪圣诞老人,我们希望连续下雪,于是决定通过 CSS 为其添加动画效果,以便高效完成。
然而,我们希望根据屏幕和场景中发生的事件动态地选择雪的水平位置,当然,只有在实际运行前,我们才会知道下雪的高度(用户浏览器窗口的高度)。这意味着我们真的必须使用 CSS 过渡,因为在运行时编写 CSS 动画会很快变得非常复杂(数以百计的雪花意味着数百个新的样式规则)。
因此,我们采取了大家应该熟悉的方法:
snowFlake.style.transform = 'translate(' + snowLeft + 'px, -100%)';
// wait a frame
snowFlake.offsetWidth;
snowFlake.style.transitionProperty = 'transform';
snowFlake.style.transitionDuration = '1500ms';
snowFlake.style.transform = 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)';
关键在于“等待框架”注释。为了成功开始过渡,浏览器必须确认该元素位于起始位置。您可以采用以下几种方法。最常见的方式之一是读取一个会强制浏览器计算布局的元素属性,从而确保它知道该元素在转换为结束位置之前具有起始位置。通过这种方式,您可以恭喜自己精通浏览器内部机制,但每次按键时仍然会感到不知所措。
相比之下,等效的 element.animate()
调用非常清晰,能够准确说明其用途:
snowFlake.animate([
{transform: 'translate(' + snowLeft + 'px, -100%)'},
{transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
还有很多其他选择。与对应的 CSS 类似,网络动画也可以延迟和迭代:
snowFlake.animate([
{transform: 'translate(' + snowLeft + 'px, -100%)'},
{transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], {
duration: 1500,
iterations: 10,
delay: 300
});
AnimationPlayer
element.animate()
实际上会返回 AnimationPlayer 对象,随着越来越多的网页动画规范的推出,该对象变得越来越重要。JavaScript 和 CSS 创建的动画都将有关联的 AnimationPlayer,从而能够以实用且有趣的方式无缝组合它们。
不过目前,AnimationPlayer 只有两项功能,这两项功能都非常实用。您可以随时使用 AnimationPlayer.cancel()
取消动画:
var player = snowFlake.animate([
{transform: 'translate(' + snowLeft + 'px, -100%)'},
{transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
// less than 1500ms later...changed my mind
player.cancel();
而且,对于过去尝试围绕 CSS 动画或过渡构建动画系统的所有人来说,让每一个人都松了一口气,网络动画在完成时总会触发事件:
var player = snowFlake.animate([
{transform: 'translate(' + snowLeft + 'px, -100%)'},
{transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
player.onfinish = function(e) {
console.log('per aspera ad terra!');
}
试试看
Chrome 36 现已全面推出,马上进入 Beta 版阶段!如果您想尝试,请尝试使用 Chrome 36 中的原生实现。不过,还有一个 Web Animations polyfill,它可以将完整 Web Animations 规范中所占的比重大幅增加到所有现代、经典的浏览器。
您可以试用雪花效果演示,尝试同时使用原生版本 element.animate()
和 polyfill。
请与我们分享您的想法
事实上,这里只是对即将推出的功能进行了预览,发布的目的是为了立即获取开发者的反馈。我们现在还不确定我们是否涵盖了所有用例,或者打磨了当前动画 API 的每个粗糙边缘。我们了解并真正做到这一点的唯一方法是让开发者试用,然后告诉我们他们的想法。
这篇博文的评论当然很有价值,您可以通过 public-fx 邮寄名单将对标准本身的评论发送给 CSS 和 SVG 工作组。
更新,2014 年 10 月:Chrome 39 增加了对与控制播放相关的另外几种方法的支持,例如 play()
、pause()
和 reverse()
。此外,它还支持通过 currentTime
属性跳转到动画时间轴上的特定点。您可以在这个新演示中了解此功能的实际运作方式。
感谢 Addy Osmani 和 Max Heinritz 提供这篇博文的帮助。