实现动画之CSS与JavaScript对比

曾经某个时期,大多数开发者使用 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) on CodePen.

结果证实了大多数网上的结论,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 动画不好吗,当然不是。实际上,在实现一些简单的状态变换(比如翻转)并不要求对老版本浏览器兼容时 CSS 动画是非常方便的。3D 变换经常能有非常好的表现(iOS7是个例外)。而且对于喜欢把所有动画实现都放在 CSS 层的开发者来说 CSS 动画非常有吸引力。但是,基于 JavaScript 的动画灵活性更高,能更好的实现复杂的动画和大量的交互。并且和你听说的不一样,它能有和 CSS 动画一样,甚至更好的性能。

当和jQuery.animate()进行比较时,我能够理解为什么 CSS 动画会那么受欢迎了。谁不想要 10 倍的性能提升呢。但是很快就不用在 jQuery 和 CSS 中进行选择了,基于 JavaScript 的工具 GSAP 提供了全新的可能性,也消除了性能的差距。

这篇文章不是要说 GSAP 或是任何其他的库;而是要说 JavaScript 动画不应该背上坏名声。实际上,JavaScript 是搭建健壮的,灵活的动画系统的唯一选择。另外,我也想让大家看到 CSS 动画中令人失望的部分,这样,你可以对动画实现的方式进行更科学的选择。

Web Animation 标准能解决问题吗?

W3C 正在制定一份新的有关解决 CSS 动画和变换缺点的标准,提供更好的控制和更多的功能。从很多方面来说它确实有很大的进步,但它也是有缺陷的(其中的一些方面甚至是不可能的,它们会和现有的合法的 CSS 标准发生冲突,例如,独立的变换控制组件看起来是不可能 的)。但那是另一个话题了,我们可以看看事情会如何发展。毕竟还是有很多聪明人在为这份标准努力的。

原文地址:https://www.cnblogs.com/jianxian/p/8977408.html

时间: 2024-11-03 19:36:51

实现动画之CSS与JavaScript对比的相关文章

桃园三结义之HTML、CSS、JavaScript

需要解释一下,这篇文章不是讲核心技术的,我也只是刚刚接触,在这里只是跟大家一起认识一下HTML.CSS.JavaScript 牛腩新闻发布系统都快敲完了,系统中牛老师也对HTML.CSS.JavaScript做了简单介绍,而且整个系统的前台都在使用HTML和CSS.根据牛老师的介绍也只能对HTML.CSS.JavaScript有个一知半解,但是敲代码的过程中对于HTML与CSS的交互原理一直不理解.通过查资料才慢慢解开了这三位大侠的庐山真面目.  最近下载了一个懒人听书软件,每天晚上睡觉前总

原生js判断css动画结束 css 动画结束的回调函数

原文:原生js判断css动画结束 css 动画结束的回调函数 css3 的时代,css3--动画 一切皆有可能: 传统的js 可以通过回调函数判断动画是否结束:即使是采用CSS技术生成动画效果,JavaScript仍然能捕获动画或变换的结束事件: transitionend事件和animationend事件标准的浏览器事件,但在WebKit浏览器里你仍然需要使用webkit前缀,所以,我们不得不根据各种浏览器分别检测事件 var transitions = { 'transition':'tra

HTML、XHTML、CSS与JavaScript入门经典pdf

下载地址:网盘下载 内容介绍: 自从网站诞生以来,用于构建网站的语言就一直在不断地演化.现在一系列最佳实践已经出现,使用HTML或XHTML创建基本的网页,使用CSS控制它们的外观并使它们更加引人注目,使用JavaScript添加交互功能.<HTML.XHTML.CSS与JavaScript入门经典>一书假设您以前没有任何经验,这些宝贵的资源有助于如何使用最新的Web标准.不管您是期待编写第一个网页的初学者,还是急需提升编程技能的资深程序员,都会发现对这些基本语言的实践指导,以及有经验的Web

使用CSS和JavaScript创建基本的视差滚动效果

网页设计中2015年最主要的趋势无疑是视差滚动效应,没有任何迹象正在减弱.视差滚动将页面转换为有趣的幻灯片,其中页面上的不同元素相对于页面的滚动以不同的速度移动.在本教程中,我们将熟悉如何在CSS和JavaScript中创建基本的视差滚动页面,并深入了解整个过程中的shebang. ? 视差滚动效果的解剖 维基百科简洁地将视差滚动效果定义 为: "计算机图形学中的一种特殊的滚动技术,其中背景图像通过相机移动比前景图像慢,在2D视频游戏中产生深度幻觉并增加沉浸感." 由于它属于网页,视差

HTML、CSS、JavaScript的详细知识点及学习顺序

HTML.CSS.JavaScript的学习顺序一般为html,css,javascript HTML.CSS.JavaScript的详细知识点介绍: 1. HTML 包含文字.图片.视频等. 或为标题加入背景图片.颜色变化,标题字体.比如,就像网页的外衣.样式是表现.2. CSS 边框等.所有这些用来改变内容外观的东西称之为表现. 是用来实现网页上的特效效果.如:鼠标滑过弹出下拉菜单.或鼠标滑过表格JavaScript3. 的背景颜色改变.还有焦点新闻(新闻图片)的轮换.可以这么理解,有动画的

JS动画和CSS动画

一. JS动画和CSS动画区别. CSS实现动画:animation transition transform JS实现动画:setInterval  setTimeout  requestAnimationFrame JS动画: 优点: 1. 过程控制,可以在动画播放过程中对动画进行控制:开始.暂停.回放.终止.取消都是可以做到的. 2. 动画效果比css3动画丰富,有些动画效果,比如曲线运动,冲击闪烁,视差滚动效果,只有JavaScript动画才能完成. 3. CSS3有兼容性问题,而JS大

Web前端开发基础:HTML、CSS、JavaScript分别实现什么功能?

相信正在学习Web前端知识的小伙伴们都知道,学习Web前端开发基础技术需要掌握:HTML.CSS.JavaScript,那么这三个都是分别实现什么功能的呢?下面和小编一起来看看吧! 一.HTML是网页内容的载体 内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字.图片.视频等. 在这里小编建了一个前端学习交流扣扣群:132667127,我自己整理的最新的前端资料和高级开发教程,如果有想需要的,可以加群一起学习交流 二.CSS样式是表现 就像网页的外衣,比如:标题字体.颜色变化.为标题

web前端入门到实战:HTML、CSS、JavaScript分别实现什么功能?

学习Web前端开发基础技术需要掌握:HTML.CSS.JavaScript,那么这三个都是分别实现什么功能的呢?下面和小编一起来看看吧! 一.HTML是网页内容的载体 内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字.图片.视频等. 二.CSS样式是表现 就像网页的外衣,比如:标题字体.颜色变化.为标题加入背景图片.边框等. 所有这些用来改变内容外观的东西称之为表现. 三.JavaScript是用来实现网页上的特效效果 比如:鼠标滑过弹出下拉菜单.鼠标滑过表格的背景颜色改变.焦点新

宏观视角下的浏览器:05 | 渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的?

前言:该篇说明:请见 说明 —— 浏览器工作原理与实践 目录 在上一篇文章中我们介绍了导航相关的流程,那导航被提交后又会怎么样呢?就进入了渲染阶段.这个阶段很重要,了解其相关流程能让你 “看透” 页面是如何工作的,有了这些知识,你可以解决一系列相关的问题,比如能熟练使用开发者工具,因为能够理解开发者工具里面大部分项目的含义,能优化页面卡顿问题,使用 JavaScript 优化动画流程,通过优化样式表来防止强制同步布局,等等. 既然它的功能这么强大,那么今天,我们就来好好聊聊 渲染流程. 通常,我