CSS vs. JS Animation: 哪个更快?

CSS vs. JS Animation: 哪个更快?

基于JavaScript的动画竟然已经默默地比CSS的transition动画快了?而且,Adobe和 Google竟然一直在发布可以媲美原生应用的富媒体移动站点?

这篇文章将会逐点讲解基于JavaScript的DOM动画库,比如Velocity.js和GSAP,是如何比jQuery和基于CSS的动画库高效的。

jQuery

让我们先从这个事实开始:JavaScript和jQuery被错误的混淆了。JavaScript的动画是快的,但是jQuery的动画慢。为什么?因为虽然jQuery很强大,但是它的目标从来不是为了成为一个高效的动画引擎。

  • jQuery不能避免布局震荡因为它的代码除了动画还提供了很多功能。

  • jQuery的内存消耗经常触发垃圾回收,导致动画卡住

  • jQuery使用setInterval而不是requestAnimationFrame (RAF)为了避免一些bug

注意,布局震荡引起了动画开始处的卡顿,垃圾回收导致了动画进行中的卡顿,RAF的缺席导致了帧率低。

实现的例子

避免布局震荡,包括简单地合并DOM查询和DOM更新:

var currentTop,
currentLeft; /* 有布局震荡 */
currentTop = element.style.top; /* QUERY */
element.style.top = currentTop + 1; /* UPDATE */ currentLeft = element.style.left; /* QUERY */
element.style.left = currentLeft + 1; /* UPDATE */ /* 没有布局震荡 */
currentTop = element.style.top; /* QUERY */
currentLeft = element.style.left; /* QUERY */ element.style.top = currentTop + 1; /* UPDATE */
element.style.left = currentLeft + 1; /* UPDATE */

发生在更新之后的查询会强制浏览器立马重新布局,并计算给出页面样式的计算值(把更新的影响考虑在内)。这对于运行于16ms间隔的动画来讲,会产生巨大的开销。

同样,实现RAF并不需要对既有代码改动很大。让我们来对比一下RAF的实现和setInterval的实现:

var startingTop = 0;

/* setInterval: 每16ms运行一次来达到60fps (1000ms/60 ~= 16ms). */
setInterval(function() {
/* 由于这里的代码会在1s内执行60次,所以我们把top属性每秒1单位的增长分成60份 */
element.style.top = (startingTop += 1/60);
}, 16); /* requestAnimationFrame: 不管浏览器是否处于最优状态,都试图运行在60fps */
function tick () {
element.style.top = (startingTop += 1/60);
} window.requestAnimationFrame(tick);

RAF极大限度地提高了动画的性能。而您只需要修改为数不多的代码。

CSS Transitions

CSS transitions的动画性能优于jQuery,它把动画的逻辑交给了浏览器本身。这会有助于:1)优化DOM交互和内存消耗以避免卡顿,2)在底层借助RAF的特性,3)强制硬件加速(借助GPU的能力来提高动画性能)。

然而,实际情况是,这些优化可以直接通过JavaScript来实现,GSAP已经致力于此多年。Velocity.js,一个新的动画引擎,不止借助于上述技术,还应用了其他方法--我们将很快探讨。

明白JavaScript动画可以媲美CSS动画库这一事实,只是我们计划的第一步。第二步是我们要明白JavaScript动画可以比CSS动画还快。

让我们从检查CSS动画库的缺陷开始:

  • Transitions的强制硬件加速是使GPU加速,然而这反而会导致GPU强压状况下动画的卡顿。这些影响在移动设备上更为严重。(特别地,这个卡顿是由于数据在浏览器的主线程和排序线程间传递的开销导致的。一些CSS属性,比如transforms和opacity,是不受这个开销影响的。)Adobe在这里阐述了这个问题。

  • Transitions在IE10以下有兼容问题, 这在PC端站点会很容易导致问题发生,因为IE8和IE9依然很流行

  • 因为transitions并不是被JavaScript控制(它们只是被JavaScript触发),浏览器并不知道如何同步地使用JavaScript代码来操控优化transitions。

相反地:基于JavaScript的动画库,可以自己决定什么时候使用硬件加速,可以兼容所有版本的IE,并且它们非常适合批量动画优化。

我的建议是,当您只是开发移动站点,并且您的动画只包含简单的状态变化时,可以使用原生CSS transitions。在这种情况下,transitions算是一种高效并且原生的解决方案,并且可以把所有的动画逻辑只放在css中,避免了因为引入JavaScript库而导致页面臃肿。但是,如果您正在设计复杂的UI,或者正在开发具有状态UI的应用程序,请使用JavaScript动画库,它可以使您的动画保持高性能,使您的工作流程保持可控。特别是在管理CSStransitions方面做得很棒的一个库是 Transit

JavaScript Animation

Okay,所以JavaScript在性能上可以占上风。但是JavaScript究竟可以快多少呢?其实,它已经快到可以创建复杂的,通常只能用WebGL构建的3D animation demo。已经快到可以创建通常只能用Flash或者影效处理做到的multimedia teaser。已经快到可以创建通常只能用canvas构建的virtual world

为了直观比较动画库的领先性能,包括Transit(内部使用CSS transitions),请查阅Velocity的文档,在VelocityJS.org

依然存在问题:JavaScript究竟如何达到高性能?下面是基于JavaScript的动画库能实现的优化列表:

  • 为了减小布局震荡,将整个动画中涉及到DOM同步化到堆栈中。

  • 缓存链式调用中的属性值,以尽量减少DOM查询(它是影响DOM动画性能的致命弱点)的发生。

  • 在同一个跨同级元素调用中缓存单位转换比率(例如PX到%、em等)。

  • 当样式更新在视觉上不明显时,跳过更新。

回顾之前讲的布局震荡,Velocity.js利用这些最佳实践来缓存动画的结束值,这些值会被重用为之后动画的开始值,从而避免再次查询DOM元素的初始值:

$element
/* 将元素向下滑动到视图中。 */
.velocity({ opacity: 1, top: "50%" })
/* 延迟1000ms,元素滑动出视图 */
.velocity({ opacity: 0, top: "-50%" }, { delay: 1000 });

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

浏览器最终可以自己执行很多相同的优化,但这样做将需要极大地限制开发人员编写动画代码的方式。因此,同样的原因,jQuery不使用RAF(见上文),浏览器也永远不会强加优化,即使这些优化只有非常小的可能会打破规范或偏离预期的行为。

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

  • GSAP是一种快速、功能丰富的动画平台。Velocit是一个轻量级工具,可以极大地提高UI动画性能和工作流程。

  • GSAP需要许可费。Velocity是通过许MIT开源的。

  • 性能都很优异,GSAP和Velocity在真实项目中没有区别。

我的建议是:当您需要精确的控制(例如重映,暂停/恢复/搜索)、运动(例如Bezier曲线路径),或复杂的分组/排序时,使用GSAP。这些特性对于游戏开发和某些niche应用非常重要,但在Web应用程序的UI中并不常见。

Velocity.js

定位GSAP功能丰富,并不意味着Velocity功能单一。相反地,在压缩后只有7Kb的文件中,Velocity不仅提供了jQuery$.animate()的所有功能,而且提供了color animation,transforms,loops,easings,class animation和scrolling。

简而言之,Velocity是jQuery、jQuery UI和CSStransitions的最佳组合。

进一步,从方便的角度,Velocity在底层使用jQuery的$.queue()方法,因此可以无缝地与jQuery的$.animate(), $.fade()$.delay()函数交互。并且,由于Velocity的语法和$.animate()一致,您页面的代码不需要修改

让我们快速看一下Velocity.js。在基础动画上,Velocity和$.animate()一样:

$element
.delay(1000)
/* 使用Velocity的2000ms内改变元素top属性的动画*/
.velocity({ top: "50%" }, 2000)
/* 当上面Velocity动画执行完时,使用标准的jQuery方法来使元素淡出*/
.fadeOut(1000);

在高级动画上,复杂的滚动场景和三维动画都可以创建——只需要两行简单的代码:

$element
/* 在1000ms内,浏览器滚动到这个元素的顶部 */
.velocity("scroll", 1000)
/* 之后使元素绕着它的Y轴旋转360度。 */
.velocity({ rotateY: "360deg" }, 1000);

结束语

Velocity的目标是保持领先的DOM动画性能和便捷。本文的重点是前者。请去VelocityJS.org学习更多关于后者的知识。

在我们结束之前,记得_*一个高性能的UI不仅仅是选择合适的动画库_。页面的其余部分也应该优化。从下面这些奇妙的Google话题中学习更多:

本文转载自:众成翻译

译者:凯小凯

审校: betsey

链接:http://www.zcfy.cc/article/4635

原文:https://davidwalsh.name/css-js-animation

CSS vs. JS Animation: 哪个更快的更多相关文章

  1. CSS3动画 相比JS Animation 哪个更快?

    CSS vs. JS Animation: 哪个更快? 基于JavaScript的动画竟然已经默默地比CSS的transition动画快了?而且,Adobe和 Google竟然一直在发布可以媲美原生应 ...

  2. CSS 和 JS 动画哪个更快

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

  3. JQuery动画插件Velocity.js发布:更快的动画切换速度

    5月3日,Julian在其GitHub上发布了Velocity.js.Velocity.js是一款动画切换的jQuery插件,它重新实现了jQuery的$.animate()方法从而加快动画切换的速度 ...

  4. Velocity.js发布:更快的动画切换速度

    Velocity.js是一款动画切换的jQuery插件,它重新实现了jQuery的$.animate()方法从而加快动画切换的速度.Velocity.js只有7k的大小,它不仅包含了$.animate ...

  5. 自从用了Less 编写css,你比以前更快了~

    之所以用这个标题呢,主要是最近调侃杰伦太有意思了. 好吧,开个玩笑而已. 如果你了解过Less,并对之很熟悉,就不用往下看了. 如果你没用过,恭喜,这是一个入门级的教程,学会了它,可以为你节省10%的 ...

  6. 自从用了Less 编写css,你比以前更快了~(sublime编译)

    之所以用这个标题呢,主要是最近调侃杰伦太有意思了. 好吧,开个玩笑而已. 如果你了解过Less,并对之很熟悉,就不用往下看了. 如果你没用过,恭喜,这是一个入门级的教程,学会了它,可以为你节省10%的 ...

  7. CSS VS JS动画,哪个更快[译]

    英文原文:https://davidwalsh.name/css-js-animation 原作者Julian Shapiro是Velocity.js的作者,Velocity.js是一个高效易用的js ...

  8. 让你的 Node.js 应用跑得更快的 10 个技巧(转)

    Node.js 受益于它的事件驱动和异步的特征,已经很快了.但是,在现代网络中只是快是不行的.如果你打算用 Node.js 开发你的下一个Web 应用的话,那么你就应该无所不用其极,让你的应用更快,异 ...

  9. 更轻更快的Vue.js 2.0与其他框架对比(转)

    更轻更快的Vue.js 2.0 崭露头角的JavaScript框架Vue.js 2.0版本已经发布,在狂热的JavaScript世界里带来了让人耳目一新的变化. Vue创建者尤雨溪称,Vue 2.0  ...

随机推荐

  1. Java通过接口实现匿名类的实例

    package com.chase.test; /** * 通过接口实现匿名类的实例 * * @author Chase * * @date 2013-10-18 下午04:28:17 * * @ve ...

  2. 【转载】Java IO 转换流 字节转字符流

    字节流输入字节流:---------| InputStream 所有输入字节流的基类. 抽象类.------------| FileInputStream 读取文件的输入字节流.----------- ...

  3. 【转载】Java IO基础总结

    Java中使用IO(输入输出)来读取和写入,读写设备上的数据.硬盘文件.内存.键盘......,根据数据的走向可分为输入流和输出流,这个走向是以内存为基准的,即往内存中读数据是输入流,从内存中往外写是 ...

  4. iterm2 快捷键设置

    单词跳转 设置option+ 左右键

  5. 如何解决windows docker共享目录不支持符号链接(do not support symlinks)?

    windows使用docker toolbox,搭建前端开发环境时,在共享目录使用npm安装前端依赖时,发现报错,无法使用符号连接. 这里有一个帖子专门讨论这个问题,感兴趣可以看一下: https:/ ...

  6. 操作符重载、继承(day08)

    二十 操作符重载 函数操作符"()" 功能:让对象当做函数来使用 注:对参数的个数.返回类型没有限制 eg: class A{...}; A a; //a.operator()(1 ...

  7. [luogu3231 HNOI2013] 消毒 (二分图最小点覆盖)

    传送门 Description 最近在生物实验室工作的小T遇到了大麻烦. 由于实验室最近升级的缘故,他的分格实验皿是一个长方体,其尺寸为abc,a.b.c 均为正整数.为了实验的方便,它被划分为abc ...

  8. Docker创建Mysql容器并通过命令行连接到容器

    拉取网易蜂巢的mysql-server:5.6 docker pull hub.c.163.com/nce2/mysql:5.6 创建mysql5.6容器 1master+3个slave docker ...

  9. 3. IDEA 的样式设置和快捷键设置

    一.样式设置 首先打开IDEA之后,点击任务栏的“File”→Settings 二.设置快捷键 1.首先打开IDEA之后,点击任务栏的“File”. 2.在下拉列表中中选择“Settings” 3.在 ...

  10. tp5 前置方法

    Route::any('adminapi/v1/login','adminapi/v1.login/login');Route::any('adminapi/v1/first','adminapi/v ...