Heim  >  Artikel  >  Web-Frontend  >  CSS vs. JS-Animationen: Wer ist schneller?

CSS vs. JS-Animationen: Wer ist schneller?

大家讲道理
大家讲道理Original
2016-11-10 11:53:141130Durchsuche

Dieser Artikel ist eine Übersetzung aus „CSS vs. JS Animation: What is Faster?“ von Julian Shapiro. Julian Shapiro ist auch der Schöpfer von Velocity.js. Dies ist eine sehr effiziente, einfache und benutzerfreundliche JS-Animationsbibliothek. Er verfügt über hervorragende Kenntnisse in der Webanimation.

Wie ist es möglich, dass Javascript-Animationen immer so schnell wie CSS-Übergänge oder sogar schneller sind? Was ist das Geheimnis? Wie machen Adobe und Google ihre medienreichen mobilen Websites genauso schnell wie native Apps? CSS vs. JS-Animationen: Wer ist schneller?

In diesem Artikel erfahren Sie Schritt für Schritt, warum Javascript-basierte DOM-Animationsbibliotheken (wie Velocity.js und GSAP) effizienter sein können als jQuery- und CSS-basierte Animationsbibliotheken.

jQuery

Beginnen wir mit den Grundlagen: Javascript und jQuery dürfen nicht verwechselt werden. Javascript-Animationen sind schnell, während jQuery-Animationen langsam sind. Warum? Denn obwohl jQuery äußerst leistungsfähig ist, besteht sein Designziel nicht darin, eine effiziente Animations-Engine zu sein:

jQuery kann Layout-Thrashing nicht vermeiden (manche Leute übersetzen es gerne als „Layout-Thrashing“, was wird (redundantes Relayout/Reflow) verursachen, da sein Code nicht nur für Animationen, sondern auch in vielen anderen Szenarien verwendet wird.
  • jQuery verbraucht viel Speicher und löst häufig eine Speicherbereinigung aus. Es kann leicht passieren, dass die Animation hängen bleibt, wenn die Garbage Collection ausgelöst wird.
  • jQuery verwendet setInterval anstelle von reqeustAnimationFrame(RAF), da RAF aufhört zu feuern, wenn das Fenster den Fokus verliert, was zu jQuery-Fehlern führt. (Derzeit verwendet jQuery bereits RAF)
  • Beachten Sie, dass Layout-Thrashing dazu führt, dass die Animation zu Beginn einfriert, und dass das Auslösen der Garbage Collection dazu führt, dass die Animation während des laufenden Prozesses einfriert. Verwenden Sie kein RAF. Dies führt dazu, dass die Bildrate der Animation niedrig ist.
Implementierungsbeispiel

Um Layout-Thrashing zu vermeiden, müssen wir stapelweise auf das DOM zugreifen und es aktualisieren.

Zugriffsvorgänge nach einem Aktualisierungsvorgang zwingen den Browser, den Stil des Seitenelements neu zu berechnen (da der aktualisierte Stil angewendet werden muss, um den richtigen Wert zu erhalten). Dies verursacht im Normalbetrieb keinen großen Leistungsverlust, verursacht jedoch einen erheblichen Leistungsaufwand, wenn es in Animationen mit einem Intervall von nur 16 ms platziert wird. Durch eine geringfügige Änderung der Reihenfolge der Vorgänge kann die Animationsleistung erheblich verbessert werden.

var currentTop,
    currentLeft;
/* 有 layout thrashing. */
currentTop = element.style.top; /* 访问 */
element.style.top = currentTop + 1; /* 更新 */
currentLeft = element.style.left; /* 访问 */
element.style.left = currentLeft + 1; /* 更新 */
/* 没有 layout thrashing. */
currentTop = element.style.top; /* 访问 */
currentLeft = element.style.left; /* 访问 */
element.style.top = currentTop + 1; /* 更新 */
element.style.left = currentLeft + 1; /* 更新 */
Ebenso lässt sich der Code durch die Verwendung von RAF nicht häufig umgestalten. Vergleichen wir den Unterschied zwischen der Verwendung von RAF und der Verwendung von setInterval:

Sie müssen den Code nur geringfügig ändern, um RAF zu verwenden, und Sie können eine enorme Verbesserung Ihrer Animationsleistung erzielen.

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);

CSS-Übergang

Die Animationslogik des CSS-Übergangs wird vom Browser ausgeführt, sodass seine Leistung besser sein kann als die der jQuery-Animation. Seine Vorteile spiegeln sich wider in:

Reduzieren Sie Verzögerungen durch Optimierung von DOM-Vorgängen und Vermeidung von Speicherverbrauch
  • Verwendung eines RAF-ähnlichen Mechanismus
  • Erzwingen Sie die Verwendung von Hardwarebeschleunigung (Verbesserung der Animationsleistung durch die GPU)
Tatsächlich kann jedoch auch Javascript diese Optimierungen nutzen. GSAP führt diese Optimierungen schon seit langem durch. Velocity.js ist eine aufstrebende Animations-Engine, die nicht nur diese Optimierungen durchführt, sondern sogar noch weiter geht. Wir werden später darüber sprechen.

Seien Sie ehrlich: Die Leistung von Javascript-Animationen mit der Leistung von CSS-Animationen vergleichbar zu machen, ist nur der erste Schritt in unserem großartigen Plan. Der zweite Schritt ist der wichtigste Schritt, denn er macht Javascript-Animationen schneller als CSS-Animationen!

Werfen wir einen Blick auf die Mängel der CSS-Animationsbibliothek:

Übergang erzwingt die Verwendung der GPU Hardwarebeschleunigung. Dadurch läuft der Browser ständig unter hoher Auslastung, was dazu führt, dass die Animation hängen bleibt. Dies ist bei mobilen Browsern noch schwerwiegender. (Es ist zu beachten, dass die Leistung besonders stark beansprucht wird, wenn häufig Daten zwischen dem Hauptthread des Browsers und dem Synthesethread übertragen werden, sodass es leicht zu Verzögerungen kommen kann. Einige CSS-Eigenschaften sind nicht betroffen. Darüber spricht der Blog von Adobe.
  • Browser unter IE 10 unterstützen den Übergang nicht. Derzeit erfreuen sich IE8 und IE9 noch großer Beliebtheit.
  • Der Übergang kann nicht vollständig durch Javascript gesteuert werden (der Übergang kann nur durch Javascript ausgelöst werden), da der Browser nicht weiß, wie er die Animation durch Javascript steuern und die Leistung der Animation optimieren kann zur gleichen Zeit.
  • Andererseits: Javascript kann bestimmen, wann die Hardwarebeschleunigung aktiviert werden soll, es kann alle Versionen des IE unterstützen und es kann Batch-Animationen vollständig optimieren.
Javascript-Animation
我的建议是:当你只在移动平台上开发,并且动画只是简单的状态切换,那么适合用纯 CSS transition。在这种情况下,transition 
是高性能的原生支持方案。它可以让你将动画逻辑放在样式文件里面,而不会让你的页面充斥 Javascript 
库。然而如果你在设计很复杂的富客户端界面或者在开发一个有着复杂UI状态的 
app。那么我推荐你使用一个动画库,这样你的动画可以保持高效,并且你的工作流也更可控。有一个特别的库做的特别棒,它可以用 Javascript 
控制 CSS transition。这就是 Transit。

  所以 Javascript 可以比 CSS transition 性能更好。但是它到底有多块呢?它快到足够可以构建一个3D 动画的demo,通常需要用到 WebGL 才能完成。并且它快到足够搭建一个多媒体小动画,通常需要 Flash 或者 After Effects 才能完成。并且它还快到可以构建一个虚拟世界,通常需要 canvas 才能完成。

  为了更直接的来比较主流动画库的性能,包括 Transit(使用了 CSS transition),让我们打开Velocity的官方文档。

  之前那个问题还在:Javascript 是如何达到高性能的呢?下面是一个列表,列举了基于 Javascript 的动画库能做的事情:

  • 同步DOM -> 在整个动画链中微调堆栈以达到最小的layout thrashing。

  • 缓存链式操作中的属性值,这样可以最小化DOM的查询操作(这就是高性能 DOM 动画的阿喀琉斯之踵)

  • 在同一个跨同层元素的调用中缓存单位转化比率(例如px转换成%、em等等单位)

  • 忽略那些变动小到根本看不出来的DOM更新

  让我们重新温习下之前学到的关于layout thrashing的知识点。Velocity.js 运用了这些最佳实践,缓存了动画结束时的属性值,在紧接的下一次动画开始时使用。这样可以避免重新查询动画的起始属性值。

$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%。

  浏览器也可以使用与此类似的优化,但是要做这些事情太过激进,使用场景也会受到限制,开发者就有可能会写出有bug的动画代码。jQuery就是因为这个原因没有使用RAF(如上所说),浏览器永远不会强行实施可能打破规范或者可能偏离期望行为的优化。

  最后,让我们来比较下两个Javascript框架(velocity.js 和 GSAP)。

  • GASP 是一个快速且功能丰富的动画平台。Velocity则更为轻量级,它大大地改善了UI动画性能和工作流程。

  • GSAP 需要付费才能用于商业产品。Velocity 是完全免费的,它使用了自由度极高的 MIT 协议。

  • 性能方面,两者几乎相当,很难区分胜负。

我个人推荐在你需要如下功能时使用 GSAP:精确控制时间(例如 remapping,暂停/继续/跳过),或者需要动作(例如:贝赛尔曲线路径),又或者复杂的动画组合/队列。这些特性对游戏开发或者复杂的应用很重要,但是对普通的 web app 的 UI 不太需要。

 Velocity.js

  之前提到了 GSAP 有着丰富的功能,但这不代表 Velocity 的功能简单。相反的,Velocity 在 zip 压缩之后只有 7kb,它不仅仅实现了 jQuery animate 方法的所有功能,还包含了 颜色、transforms、loop、easings、class 动画和滚动动画等功能。

  简单的说就是 Velocity 包含了 jQuery、 jQuery UI 和 CSS transition 的功能。

  更进一步从易用性的角度来讲,Velocity 使用了 jQuery 的$.queue() 方法,因此可以无缝过渡到 jQuery 的$.animate()、$.fade()和$.delay()方法。并且 Velocity 的语法和$.animate()一摸一样,所以我们根本不需要修改页面的现有代码。

  让我们快速过一下 Velocity.js 的例子:

$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);

  如下是一个高级用法:滚动网页到当前元素并且旋转元素。这样的动画只需要简单的几行代码:

$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);

 总结

  Velocity 的目标是成为 DOM 动画领域性能最好易用性最高的库。这篇文章主要关注了性能方面。易用性方面可以前往 VelocityJS.org 了解。

  在结束之前,请记住一个高性能的 UI 绝不仅仅是选择一个正确的动画库。页面上的其他代码也需要优化。可以看看Google那些非常棒的演讲:

Jank Free

Rendering Without Lumps

Faster Websites


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn