原文地址:http://css-tricks.com/myth-busting-css-animations-vs-javascript/

译文地址:https://github.com/classicemi/blog/issues/3

曾经某个时期,大多数开发者使用 jQuery 给浏览器中的元素添加动画。让这个淡化,让那个扩大,很简单。随着互动的项目越来越复杂,移动设备的大量增加,表现性能变得越来越重要。Flash 被抛弃,有天赋的动画开发者使用 HTML5 去实现过去从未实现的效果。他们需要更好的工具去开发复杂的动画序列并获得最好的性能。jQuery 并不能够做到。浏览器日渐成熟的同时也开始提供了一些解决方案。

最被广泛接受的方案是使用 CSS 动画(以及 Transitions)。几年中,它成为了业内的热门话题,在各种研讨会上,“硬件加速”和“移动端友好”之类的说法总是不绝于耳。基于 JavaScript 的动画总是被当做过时的甚至是“肮脏的”。但是真的是这样吗?

作为一个对动画和表现深深着迷的人,我如饥似渴地投入了 CSS 的怀抱,但当我开始发现了一些大问题后,我却没有深入研究进去。我被震惊了。

这篇文章用于揭示基于 CSS 的动画的一些重大缺陷,这样你可以避免碰到曾经困扰我的问题,同时也教会大家决定何时用 JS 动画以及何时用 CSS 动画。

缺少独立的 scale/rotation/position 控制

对元素的尺寸,旋转以及位置设置动画是非常常见的。在 CSS 里,这些设置都被塞进了transform属性当中,这样就不能够真正地独立控制它们。例如,你该如何用不同的时间和缓动函数去分别控制元素的rotationscale属性?可能这个元素会不停的震荡,并且你想去旋转它。这只有用 JavaScript 才能实现。

See the Pen Independent Transforms by GreenSock (@GreenSock) on CodePen.

在我看来,这是 CSS 动画一个很显著的问题,但是如果你只需要开发一些简单的动画效果,它们同时触发整个 Transform 状态的话,这也不是什么大问题。

表现性能

大多数比较都会拿 CSS 动画和 jQuery 相比,因为 jQuery 的使用非常普遍(就好像 JavaScript 和 jQuery 是同义词一样)。但是 jQuery 的动画性能很差也是众所周知的。较新的 GSAP 同样是基于 JavaScript 的,但是毫不夸张的说它的性能相比于 jQuery 提升了近 20 倍。因此,JavaScript 动画声名狼藉的部分原因我认为是 jQuery。

使用 CSS 动画的原因中,常常被提起的是“硬件加速”这个概念。听起来很高大上是吧?我们来把它分解成两个部分:

GPU 的使用

GPU 在执行类似控制像素点的移动和应用变换矩阵和透明等方面都做了优化,因此现代浏览器会试着把这方面的任务从 CPU 转交给 GPU 来完成。秘诀在于将应用动画的元素独立出来,建立一个自己的 GPU 层,因为只要一个层被创建,让 GPU 去移动那些像素点并把它们组合起来是很轻松的一件事。不同于以每秒 60 次的速度计算每个像素点的位置,GPU 可以把大量的像素以层的方式储存,然后我们就可以通过像“把那块像素向上移动 10 像素再向下移动 5 像素”这样的方式对像素进行操作了。

注解:GPU 是有图像存储空间限制的,因此将每个元素都转换为一个层是不合适的。一旦 GPU 的存储空间用完了,速度就会急剧降低。

通过 CSS 声明动画能够让浏览器决定哪个元素应该获得 GPU 层,并根据实际情况分配资源。很方便。

但是你知道你可以用 JavaScript 做到同样的事情吗?用一个 3D 特性的触发器(比如translate3d()或者matrix3d())来让浏览器为这个元素开辟一个 GPU 层。所以 GPU 加速不仅仅是为 CSS 动画准备的,JavaScript 动画一样可以受益!

另外记住,不是所有的 CSS 属性在 CSS 动画中都能够获得 GPU 的加速。实际上,大多数是不能的。变换(比如 scale,rotation, translation 和 skew)和透明效果是直接受益的。所以不要想当然认为你只要用了 CSS 动画,所有的效果都得到了 GPU 的帮助,那是不对的。

将计算转移给不同的线程

“硬件加速”的另一个方面是使用 CPU 的不同线程来进行和动画相关的计算。再一次的,理论上听起来很美但是它实际上和性能的开销无关,开发者往往会高估它带来的好处。

首先,只有与文档流无关的属性才能真正被移交给另一个线程。所以再一次的,变换和透明度是首要受益者。而转移线程的过程中也是有开销的。在大多数动画中,图像的渲染和文档的展现已经耗费了大多数的处理器资源(这还没有算上中间动画属性本身所耗费的资源),因此转移线程所带来的好处已经微乎其微了。比如,在一个动画中,98%的资源都用来计算图像的渲染和文档流的展现,只有2%的资源用来计算位置、旋转、透明度等属性,即使你将这部分的计算速度加快了十倍,整体带来的速度提升可能也只有1%而已。

性能比较

下面的压力测试创建了一定数量的图像元素(点),并且使用动画让它们从中点沿着随机方向以随机的延迟向边缘飞去,展现了一种飞舞的粒子效果。将粒子的数量提高,观察 jQuery,GSAP 和 Zepto 的比较效果。由于 Zepto 使用了 CSS 来展现所有的动画效果,它的性能应该最好是吗?

See the Pen Speed Test: GSAP vs CSS Transitions (Zepto) vs jQuery by GreenSock (@GreenSock) onCodePen.

结果证实了大多数网上的结论,CSS 动画明显比 jQuery 要快。但是,在我测试的大多数设备和浏览器上,GSAP 的性能甚至比 CSS 还要好(在某些情况下差距还很大,比如在 Microsoft Surface RT 上 GSAP 的速度比 Zepto 创建的 CSS 动画快上 5 倍,并且在 iPad 3 iOS 7 上 GSAP 的动画变换也比 CSS Transition要快)。

Animated properties Better w/JavaScript Better w/CSS
top, left, width, height Windows Surface RT, iPhone 5s (iOS7), iPad 3 (iOS 6), iPad 3 (iOS7), Samsung Galaxy Tab 2, Chrome, Firefox, Safari, Opera, Kindle Fire HD, IE11 (none)
transforms (translate/scale) Windows Surface RT, iPhone 5s (iOS7), iPad 3 (iOS7), Samsung Galaxy Tab 2, Firefox, Opera, IE11 iPad 3 (iOS6), Safari, Chrome

到底有多快?在测试的最初版本中,有每秒渲染帧数这一量化指标,但是很快就发现并没有一个准确的方式跨浏览器去测量 FPS 的值,尤其是 CSS 动画。并且特定的浏览器会得到令人误解的数字,所以我把它移除了。你可以进行间接的测量,比如逐渐提高粒子数量,切换不同的动画引擎,观察动画的渲染质量(移动平滑稳定,粒子分散度高等等)。毕竟,我们的目标是让动画看起来好看。

一些有趣的事情:

  • 当应用动画的属性是会影响文档流的属性,比如 top/left/width/height 值时,JavaScript 的性能会更好(是 GSAP,不是 jQuery)。
  • 某些设备看起来对 Transiforms 变换做了优化,而另一些处理 top/left/width/height 的变化显得更好。尤其显著的是,老的 iOS6 在处理 CSS 动画变换时表现更好,而更新的 iOS7 系统在这方面退步了,而现在更是明显慢了。
  • 在 CSS 动画刚刚启动的时候都会有一个明显的延迟,这是由于浏览器要计算层并把数据传输至 GPU,基于 JavaScript 的动画同样存在这样的问题。所以说“GPU加速”也是有自己的开销的。(译者注:这个问题可由新的 CSS 属性will-change来解决,相关文档)
  • 在压力比较大的时候,CSS 变换创建的粒子会以一种类似带状或环状的形式喷出(这似乎是同步时序的问题,是由不同线程处理而造成的)。
  • 在一些浏览器中(比如 Chrome),当动画中的粒子数非常多的时候,文字的透明渐隐就会完全消失,但这样的情况只存在于 CSS 动画中!

尽管经过优化的 JavaScript 动画经常和 CSS 动画一样快,甚至更快,但是 CSS 处理 3D 变换的速度还是更快,但这还跟当今浏览器处理 16 元素的矩阵的方式有关(强制将数字转换为连接的字符串,再转换为数字)。好在这种情况将会改变,在大多数实际的项目中,你并不会感觉到这种区别。这段是什么意思?

我鼓励你在自己的项目中通过自己的测试去找到性能最高的实现动画的方式。不要相信 CSS 动画性能一定高的说法,也不要让上文的测试影响你自己的应用中的结果。一定要自己测试,测试,再测试。

运行时的控制和事件

一些浏览器允许你在 CSS keyframes 动画中暂停,但最多也就是这样了。你不可能在动画中寻找一个特定的时间点,不可能在半路反转动画,不可能变换时间尺度,不可能在特定的位置添加回调函数或是将他们绑定在一大堆回放事件上[?]。JavaScript 提供了很棒的控制方法,请看下面的例子:

See the Pen Impossible with CSS: controls by GreenSock (@GreenSock) on CodePen.

现代动画大多看重交互性,因此从多种起始变量通过动画变换为结束状态就显得尤其有用(例如可能是基于用户点击鼠标的位置),或者改变正在运动中的元素,提前声明式的 CSS 动画就做不到这一点。

工作流

对用两个状态之间的简单切换(比如翻转或是展开菜单),CSS 变换是很好用的。对于连续变换状态的动画,你需要使用 CSS keyframes 动画来实现,它迫使你通过百分比的方式来声明动画,就像这样:

@keyframes myAnimation {0% {opacity: 0;transform: translate(0, 0);}30% {opacity: 1;transform: translate(0, 0);}60% {transform: translate(100px, 0);}100% {transform: translate(100px, 100px);}
}
#box {animation: myAnimation 2.75s;
}

但是动画进行的时候,你难道不觉得通过时间表示比使用百分比更好吗?就像“用 1 秒钟降低透明度,再用 0.75 秒向右滑动,再过 1 秒后向下掉落”。如果你用了几个小时通过百分比的方式实现后,客户又要求你将中间的步骤用时增加 3 秒呢?你需要重新计算所有的百分比了!

创建动画的过程中常常需要进行很多的试验,尤其是针对时间和缓动方式,这是seek()方法能派上用场的地方。想象你创建了一个 60 秒长度的动画然后需要对最后 5 秒进行处理,为了看到编辑后的效果,你每次都要先等上 55 秒钟的时间才行。你可以使用这个方法直接跳过前面的时间,最后再移除这个方法,这样可以节省大量的时间。

现在创建基于 canvas 的对象以及第三方库对象的动画的场景越来越多,而 CSS 动画又只能以 DOM 元素为目标。也就是说即使你花了大量的时间研究 CSS 动画,在那样的项目中也不会有用,最后你还是不得不更换工具。

以下是一些其他的 CSS 动画不能提供的工作流程相关的便利:

  • 相对值。比如“再旋转 30 度”或是“将元素由动画开始的地方再向下移动 100 像素”。
  • 嵌套。想象把一个动画嵌套在另一个同样可以被嵌套的动画之中,等等。设想控制主动画的时候所有的动画都能同步。这样的结构能促进生成模块化的代码,利于生产和维护。
  • 进程报告。特定的动画结束了吗?如果没有,它现在处于整个过程中的什么位置?
  • 特定删除。有时候,只移除一个元素上所有影响其尺寸(或任何你认为的属性)的动画同时允许其他的动画进行是非常有用的。
  • 代码简洁。即使你不添加多余带前缀的属性,CSS keyframes 动画的代码也会非常冗长。任何想用 CSS 实现稍微复杂一点动画的人都能证实 CSS 代码最后会变得非常笨重。实际上,实现动画的 CSS 代码的体积可能都会超过 JavaScript 库的体积(在很多动画中它还能被缓存和重用)。

有限的效果

以下的任何效果你都无法通过 CSS 实现:

  • 沿着曲线运动(比如贝塞尔曲线)
  • 使用有趣的缓动效果,比如有弹性的,或是弹跳,或是粗糙的效果。虽然有cubic-bezier()这个选项,但它只允许两个控制点,因此功能也十分有限。
  • 在 CSS keyframes 动画中针对不同的属性使用不同的缓动效果。缓动会应用到整个 CSS keyframes 上。
  • 基于物理的动作。例如,有冲击效果的闪烁,或是恢复状态,就像这个Demo中的一样。
  • 滚动位置的动画。
  • 指定方向的旋转。比如沿最短方向旋转270度,或顺时针和逆时针。
  • 元素属性的动画

兼容性

基于 CSS 的动画在 IE9 及之前版本的浏览器中都无效,我们大多都讨厌适配老版本的浏览器(尤其是 IE),但现实是我们的一些客户会要求那样的支持。

对许多浏览器来说,前缀是需要的,不过你可以利用预编译工具来避免手动书写它们。

css动画和js动画比较!相关推荐

  1. css动画和js动画_CSS与JS动画:哪个更快?

    css动画和js动画 How is it possible that JavaScript-based animation has secretly always been as fast - or ...

  2. css动画 和 js动画_CSS大师的动画建议

    css动画 和 js动画 Just over a week ago we were lucky enough to have Tiffany Brown join us on the SitePoin ...

  3. 【JavaScript、CSS】css动画、js动画

    动画 js动画 css动画 Web动画的本质是元素状态改变造成的样式变更,CSS动画和JS动画的区别并不是由语言来决定的,而是由两者的特点和适用场景来判断的. CSS动画简洁高效,提升交互体验而编写的 ...

  4. css3 动画 vs js 动画

    之前被问到过,css3 动画与 js 动画孰优孰劣,脑袋的第一反应就是性能上肯定 css3 动画会好很多,但别人说不对,我就在想,不对?难道还有别的原因吗?答案是肯定的.先来看看二者实现动画的原理吧. ...

  5. 【译】CSS动画 vs JS动画

    原文地址 目前有两个主流的方法在web上创建动画:使用CSS或JS.到底选择哪种方法来实现动画,完全取决于你的项目以及你想要达到的效果. tips: 对于简单的只出现一次的过渡效果,可以采用CSS动画 ...

  6. css动画与js动画的区别

    CSS动画 优点: (1)浏览器可以对动画进行优化. 1. 浏览器使用与 requestAnimationFrame 类似的机制,requestAnimationFrame比起setTimeout,s ...

  7. 分别实现:css动画、js动画、vue动画

    一.使用css3实现动画 css3动画的核心是定义transition或 keyframes 两种. keyframes:设置多个关键帧来控控制不懂时间下动画对象属性的值,(可循环的) transit ...

  8. json动画_three.js动画(四)

    ThreeJS的动画系列分为:基础动画.相机控制.变形动画.用骨骼和蒙皮制作动画以及使用外部模型创建动画. 用骨骼和蒙皮制作动画 用骨骼来做动画时,移动一下骨骼,Three.js必须决定如何相应地迁移 ...

  9. css与 js动画 优缺点比较

    我们经常面临一个抉择:到底使用JavaScript还是CSS动画,下面做一下对比 JS动画 缺点:(1)JavaScript在浏览器的主线程中运行,而主线程中还有其它需要运行的JavaScript脚本 ...

最新文章

  1. 关于MATLAB处理大数据坐标文件2017529
  2. javascript实战pdf_《TypeScript开发实战》总结
  3. FreeSwitch安装和配置记录
  4. Netty对Protocol Buffer多协议的支持(八)
  5. 在东岸听刘元演奏萨克斯
  6. Opencv——DFT变换(实现两个Mat的卷积以及显示Mat的频域图像)
  7. 给Jquery easyui 的datagrid 每行添加操作链接
  8. 通达信自编的选股公式如何使用
  9. 程序员必备75道逻辑思维题(附答案)之二
  10. 西门子博图怎么导入库文件_【傻瓜教程】博途中库的建立与使用方法(工控公开课 今晚8点 老地方 不见不散!)...
  11. 关于php的梗儿_php是世界上最好的语言是什么梗?
  12. win7忘记开机密码怎么弄?
  13. Hold住通话有三种方式
  14. Excel制作+导出
  15. 智慧环保可视化决策系统
  16. XX大学学生选课系统需求规格说明书
  17. 七彩cms云转码_七彩CMS视频转码 2019云转码彻底开源系统版本号
  18. e3是合法浮点数吗_下面四个选项中,均是不合法的浮点数的选项是
  19. C++头文件与C语言头文件的区别
  20. Docker安装MYSQL8及内存优化

热门文章

  1. mpvue实现类似通讯录锚点
  2. JavaScript加密/解密与OpenAI的对接:生成加密对话的ChatGPT 4.0应用
  3. 【13】变分自编码器(VAE)的原理介绍与pytorch实现
  4. cubeIDE开发, stm32独立看门狗IWDG的CubeMX配置及HAL库底层实现分析
  5. 网络基础——牛客网刷题第四波
  6. Castle Monorail 缓存
  7. Django 浏览器报错 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
  8. C# MVC引用_ViewStart.cshtml,新页面如何清空Layout模板
  9. 秒杀场景的九个细节,细思极恐!
  10. java 对象查找_Java如何从数组中查找对象元素?