深入探究使JavaScript动画流畅的一些方法

基于Javascript的动画暗中同CSS过渡效果一样,甚至更加快,这怎么可能呢?而Adobe和Google持续发布的富媒体移动网站的性能可媲美本地应用,这又怎么可能呢?

本文逐一遍览了基于Javascript的DOM动画库,如Velocity.js和GSAP,看其是如何比jQuery和CSS动画效果更具性能的.
jQuery

让我们先从基础的开始: JavaScript 和 jQuery 被错误的混为一谈了. JavaScript 动画是很快的. jQuery 把它放慢了下来。为什么?因为 — 尽管jQuery非常强大 — 但成为一个性能强劲的动画引擎从来都不是jQuery的设计目标:

  • jQuery 不能避免 布局颠簸 ,这得归因于它的代码库提供了动画之外的多种用途.
  • jQuery 的内存消耗经常会触发垃圾回收,那样会 时不时的让动画定格下来.
  • jQuery 使用 setInterval 而不是 requestAnimationFrame (RAF) 来 保护新技术不受其自身的影响.

应该注意到布局颠簸就是在动画开始部分的不顺畅,垃圾回收就是造成动画期间不顺畅的元凶, 而没有使用RAF则会导致低帧率.

实现示例

避免造成布局颠簸的DOM查询和更新组合:

var currentTop,
  currentLeft;

/* With layout thrashing. */
currentTop = element.style.top; /* QUERY */
element.style.top = currentTop + 1; /* UPDATE */

currentLeft = element.style.left; /* QUERY */
element.style.left = currentLeft + 1; /* UPDATE */

/* Without layout thrashing. */
currentTop = element.style.top; /* QUERY */
currentLeft = element.style.left; /* QUERY */

element.style.top = currentTop + 1; /* UPDATE */
element.style.left = currentLeft + 1; /* UPDATE */

发生在更新之后的查询会强制浏览器对页面的计算式数据进行重新计算 (同时会把新的更新效果考虑在内). 这样就会对动画产生显著的开销,而这只是16毫秒微小间隔的运行超时.

类似的,实现 RAF 并不必须是对你的现有代码库的显著返工. 让我们拿RAF的基础实现同setInterval比较一下:

var startingTop = 0;

/* setInterval: Runs every 16ms to achieve 60fps (1000ms/60 ~= 16ms). */
setInterval(function() {
  /* Since this ticks 60 times a second, we divide the top property's increment of 1 unit per 1 second by 60. */
  element.style.top = (startingTop += 1/60);
}, 16);

/* requestAnimationFrame: Attempts to run at 60fps based on whether the browser is in an optimal state. */
function tick () {
  element.style.top = (startingTop += 1/60);
}

window.requestAnimationFrame(tick);

RAF 产生了推动动画性能的最大可能性,你可以对你的代码进行单一的变更.

CSS 转换

CSS转换通过把动画逻辑甩给浏览器本身去处理而超越了jQuery,这在以下几方面是有效果的:(1)优化DOM交互和内存消耗以避免卡顿(颠簸),(2)利用引擎的RAF原则,(3)强制硬件加速(利用GPU的能力来提高动画性能)。

然而,现实是,这些优化也可以在JavaScript中直接执行。GSAP已经这样做了多年。Velocity.js,一个新的动画引擎,不仅利用了同样的技术,而且还向前多走了几步——我们不久会探讨这些。

面对事实,JavaScript动画可以与CSS转换竞争只是我们康复计划的第一步。第二步是实现“JavaScript动画实际上可以比CSS转换更快”。

现在我们开始谈谈CSS变换的弱点:

  • transition强制硬件加速会加大GPU消耗,高负荷情形下将导致运行不流畅。这种情况在移动设备上尤为明显。(特殊情况下,比如当数据在浏览器主线程和排版线程之间传递产生的瓶颈也会导致不流畅)。某些CSS属性,比如transform和opacity,则不受这些瓶颈影响。Adobe在这里精心总结了这些问题。
  • transition在IE10以下没有用,造成的自IE8和IE9以来的桌面站点可用性问题至今仍然广泛存在。
  • 由于transition并不是由JavaScript原生控制(而仅仅是由JavaScript触发),浏览器无法获知如何与控制这些transition的JavaScript代码同步地优化他们。

相反的,基于JavaScript的动画库则可以自行确定合适开启硬件。它们原生支持各版本IE浏览器,并且它们尤其适合批量动画优化。

我的建议是仅当你单独为移动端开发且仅实现简单动画时使用原生CSS变换。这种环境下,transition是一种原生有效的解决方案,可以使你在样式表中实现所有动画逻辑,而不用添加额外的JavaScript库,从而避免你的页面变得臃肿。然而,当你在设计复杂的UI,或者是开发存在不同状态的UI的App时,你就应该使用动画库以使动画保持流畅,同时使工作流程易于管理。Transit是一个在管理CSS变换方面做得尤其优秀的库。

JavaScript 动画

好了,那JavaScript可就在性能方面占据上风了. 但Javascript究竟具体快了多少呢? 好吧 — 最初 — 对于构建一个实在的 3D动画示例 是足够快的,通常在构建中你只会看到有使用WebGL. 而构建一个 多媒体小动画 也够了,通常你看到只会使用Flash或者After Effects构建. 而构建一个 虚拟世界 也够了,通常你只会看到使用canvas构建.

为了对领先的动画库,当然还要包含Transit(它使用CSS渐变效果),进行直接的对比, 回头去看看Velocity在VelocityJS.org上的文档.

问题仍然是: JavaScript是怎样具体的达成其高水平性能的? 下面是对基于Javascript动画能够被执行这一目标的优化的一个简短清单:

  • 同步 DOM → 在整个动画链中间入栈以最小化布局抖动.
  • 为整个链式调用缓存属性值,以最小化DOM查询发生 (这些就是高性能DOM动画的坑).
  • 在同样的调用中缓存整个同级别元素的单元转换率 (比如 px 到 %, em, 等等.).
  • 当更新可能会在视觉上不可见时跳过样式更新.

回顾一下我们先前学过的关于布局颠簸的知识,Velocity.js利用这些最佳实践来缓存动画结束值以复用为随后动画的开始值,从而避免了重新查询DOM以获取元素的开始值:

$element
  /* Slide the element down into view. */
  .velocity({ opacity: 1, top: "50%" })
  /* After a delay of 1000ms, slide the element out of view. */
  .velocity({ opacity: 0, top: "-50%" }, { delay: 1000 });

在上面例子中,第二个 Velocity 调用知道它应该自动从 opacity为1 和 top为50% 开始。

浏览器本身最终能够执行许多这些相同的优化,但这样做会明显减少开发者能够制作的动画代码的方式。因此,出于同样原因,由于jQuery不使用RAF(如上所述),浏览器就不会强制优化它,甚至给出一个很小的机会去打破规格或偏离预期的行为。

最后,我们对这两个JavaScript动画库(Velocity.js 和 GSAP)互相比较一下。

GSAP 是首个动画库,用在演示JavaScript DOM 令人印象深刻的动画表现。它确实是这样,但有些缺点:

  • 在中到高负荷动画中,GSAP 的 DOM 交互开销导致动画在开始时和过程中失帧。
  • 相反于Velocity.js 是在超宽松的 MIT 许可下发布的,  GSAP 是闭源的, 并且在很多类商用时候需要许可年费。
  • 因为 GSAP 是一个完整的动画套件,是 Velocity 大小的三倍。然而,GSAP 有如此丰富功能,有助于其成为动画的瑞士军刀。

我推荐做法是在你需要精确控制定时(比如 重绘,暂停/恢复)和运动(比如贝塞尔曲线路径)的时候用 GSAP 。这些特性在游戏开发和某些特殊应用中是至关重要的,但是通常不需要用在网页应用的 UI中。

Velocity.js

引用 GSAP 丰富的特性并不代表Velocity自身在特性上是轻量级的. 相反,在压缩后仅有的7kb中,Velocity不仅仅复制了jQuery $.animate()的所有功能, 它还把颜色动画,转换,循环,easing效果,类动画还有滚动都打包了进去.

总之,Velocity是jQuery,jQuery UI,以及CSS渐变效果的最佳组合.

此外,从便利的角度看,Velocity在hood(盖子,大概意思是公共的接口)之下使用jQuery的 $.queue() 方法, 如此就可以实现同 jQuery 的 $.animate(), $.fade(), 和 $.delay() 函数的无缝互操作. 而且,由于Velocity的语法同 $.animate() 的语法是相同的, 你不需要改变页面的任何代码.

让我们快速地来看一看 Velocity.js. 在基础的层面,Velocity的行为同$.animate()一样:


$element
  .delay(1000)
  /* Use Velocity to animate the element's top property over a duration of 2000ms. */
  .velocity({ top: "50%" }, 2000)
  /* Use a standard jQuery method to fade the element out once Velocity is done animating top. */
  .fadeOut(1000);

在其最高级的层面,可以创建带有3D动画的复杂滚动场景 — 几乎只要用到两行简单的代码:

$element
  /* Scroll the browser to the top of this element over a duration of 1000ms. */
  .velocity("scroll", 1000)
  /* Then rotate the element around its Y axis by 360 degrees. */
  .velocity({ rotateY: "360deg" }, 1000);
(0)

相关推荐

  • javascript帧动画(实例讲解)

    前面的话 帧动画就是在"连续的关键帧"中分解动画动作,也就是在时间轴的每帧上逐帧绘制不同的内容,使其连续播放而成的动画.由于是一帧一帧的画,所以帧动画具有非常大的灵活性,几乎可以表现任何想表现的内容.本文将详细介绍javascript帧动画 概述 [分类] 常见的帧动画的方式有三种,包括gif.CSS3 animation和javascript git和CSS3 animation不能灵活地控制动画的暂停和播放.不能对帧动画做更加灵活地扩展.另外,gif图不能捕捉动画完成的事件.所以,

  • 浅析JavaScript动画

    今天,小学生以自己浅薄的见地,在前辈大能的基础上写这篇文章,希望给大家打开一扇窥探JavaScript(以下简称JS)动画的窗户. JS如何制造出动画效果? 结合浏览器提供的 setInterval 或 setTimeout API,高频改变DOM元素的一些属性,即可创造一个肉眼可见的动画效果.一个看起来非常流畅的JS动画除了需要良好的变换算法外,与其执行宿主也是非不开的.程序写得再好,如果浏览器过于老旧,电脑CPU性能低下,也会出现卡顿,甚至卡死. 执行一个动画函数对于浏览器来说是个苦差,设置

  • 深入探究使JavaScript动画流畅的一些方法

    基于Javascript的动画暗中同CSS过渡效果一样,甚至更加快,这怎么可能呢?而Adobe和Google持续发布的富媒体移动网站的性能可媲美本地应用,这又怎么可能呢? 本文逐一遍览了基于Javascript的DOM动画库,如Velocity.js和GSAP,看其是如何比jQuery和CSS动画效果更具性能的. jQuery 让我们先从基础的开始: JavaScript 和 jQuery 被错误的混为一谈了. JavaScript 动画是很快的. jQuery 把它放慢了下来.为什么?因为 -

  • AngularJS 实现JavaScript 动画效果详解

    AngularJS 应用中实现 JavaScript 动画效果 AngularJS 是一组用于创建单页Web应用的丰富框架,给构建丰富交互地应用带来了所有需要的功能.其中一项主要的特性就是Angular带来了对动画的支持. 我们能够在应用的部分内容当中使用动画来表明一些变化正在发生.在我上一篇文章当中,我讲到了在Angular应用中对CSS动画的支持.在这篇文章当中,我们会看到怎样利用JavaScript脚本在AngularJS应用当中生成动画效果. 在Angular当中,CSS和JavaScr

  • Javascript动画效果(4)

    前面我们自己写了一个小小的关于js动画的插件,下面我们来使用之前的框架来完成我们想要的动画效果.我们经常在淘宝网中看到,鼠标经过某一图片时,该图片有从上滚出而又从下滚入的效果,那么那种效果是如何实现的呢? 首先我们我们完成该效果的html和css代码,代码如下: html部分代码: <div id="move"> <a href="#"><i><img src="images/1.jpg"/><

  • JavaScript实现网页带动画返回顶部的方法详解

    服务器由阿里云换到了腾讯云,我的代码之前一直都是托管在git上的,但是搬家的时候,可能是着急了,之前有些新加的文件没有托管到git上,所以,就丢了. 不过无所谓了,可以重新写嘛. 之前博客的回到顶部功能是请之前的一位前端的同事帮忙写的,这次打算自己尝试一下. 返回顶部无非就是锚点. 第一个版本: <body style="height:2000px;"> <div id="topAnchor"></div> <a href=

  • Javascript动画效果(1)

    前面我们介绍了Javascript的回到顶部效果,今天呢,我们对Javascript动画做进一步的研究.在这篇博文中我们只介绍简单的匀速运动.简单的缓冲运动和简单的多物体运动后面我们还会介绍任意值变化的运动.链式运动.同时运动,同时我们还会简单的封装一个运动插件并且还会将Javascript方法和jquery方法进行比较. 1.简单的匀速运动 下面我们介绍一个demo,鼠标移入,动画向右移动(即隐藏部分显示):鼠标离开,动画向左运动(继续隐藏)整个过程都是匀速的.有了前面回到顶部效果作为基础,这

  • Javascript动画效果(2)

    在前面的文章中讲了简单的Javascript动画效果,这篇文章主要介绍我在改变之前代码时发现的一些问题及解决方法. 在前面的多物体宽度变化的例子中,我们给其增加代码:border: 4px solid #000;我们发现,鼠标移出后,宽度不是200px了,那么究竟是如何产生这种情况的呢?下面我们通过一个新的例子来分析 html代码: <div id="div1">hello</div> css代码: body,div{ margin: 0px; padding:

  • javascript动画算法实例分析

    本文实例讲述了javascript动画算法.分享给大家供大家参考.具体如下: 动画算法 Linear:无缓动效果(匀速运动): Quadratic:二次方的缓动: Cubic:三次方的缓动 Quartic:四次方的缓动: Quintic:五次方的缓动: Sinusoidal:正弦曲线的缓动: Exponential:指数曲线的缓动: Circular:圆形曲线的缓动: Elastic:指数衰减的正弦曲线缓动: Back:超过范围的三次方缓动): Bounce:指数衰减的反弹缓动. 每个效果都分三

  • Javascript动画效果(3)

    前面我们已经介绍了速度动画.透明度动画.多物体运动和任意值变化,并且我们在Javascript动画效果(二)中介绍到我们封装了一个简单的插件雏形,接下来我们对前面的动画效果进行进一步扩充,尽量将我们的框架做到更实用.在这里我们还需要了解两个运动,一个是链式运动,一个是同时运动.它们间的区别分别是:链式运动是指运动一个接着一个(一个运动完成马上进行下一个运动):而同时运动是指所有的运动同时进行.在这里,我们该如何实现呢? 1.链式运动 前面的效果中,我们已经能对任意值进行相应的变化,我们该如何在一

  • javascript动画之磁性吸附效果篇

    前面的话 上一篇,我们介绍了javascript动画之模拟拖拽效果篇.但在实际应用中,常常需要为拖拽的元素限定范围.而通过限定范围,再增加一些辅助的措施,就可以实现磁性吸附的效果 范围限定 如果我们限定元素只可以在可视范围内移动,那么就需要对其进行范围限定 首先,先要搞清楚是可视区域限定被拖拽元素 左侧范围L0 = 0 右侧范围R0 = document.documentElement.clientWidth 上侧范围T0 = 0 下侧范围B0 = document.documentElemen

随机推荐