Heim  >  Artikel  >  Web-Frontend  >  Vergleich zwischen CSS-Animation und JavaScript-Animation

Vergleich zwischen CSS-Animation und JavaScript-Animation

伊谢尔伦
伊谢尔伦Original
2017-01-16 16:37:561365Durchsuche

Vorteile der CSS3-Animation:

  • Die Leistung wird etwas besser sein und der Browser nimmt einige Optimierungen für die CSS3-Animation vor (z. B. das Erstellen einer neuen Ebene zum Ausführen der Animation)

  • Der Code ist relativ einfach

Aber seine Mängel liegen auch auf der Hand:

  • In der Animationssteuerung Nein flexibel genug

  • Schlechte Kompatibilität

Einige Animationsfunktionen können nicht implementiert werden (z. B. Scroll-Animation, Parallaxen-Scrolling usw.)

JavaScript-Animation gleicht diese beiden Mängel aus. Sie verfügt über starke Steuerungsmöglichkeiten und kann einzelne Frames steuern und transformieren. Gleichzeitig ist sie, wenn sie gut geschrieben ist, vollständig mit IE6 kompatibel und verfügt über leistungsstarke Funktionen. Bedenken Sie jedoch, dass es sich bei der Transformationsmatrix der CSS-Animation um eine Berechnung auf C++-Ebene handelt, die schneller sein muss als Berechnungen auf JavaScript-Ebene. Darüber hinaus bereitet auch die Abhängigkeit von Bibliotheken Kopfschmerzen.

Für einige komplexe gesteuerte Animationen ist die Verwendung von Javascript zuverlässiger. Wenn Sie einige kleine interaktive Effekte implementieren, sollten Sie mehr CSS in Betracht ziehen.

Basierend auf tatsächlichen Projekterfahrungen gibt es im gleichen Kontext kaum Unterschiede in der Effizienz der Animation zwischen den beiden Lösungen. Was sich stärker auf die Effizienz auswirkt, ist:

  • Ob es das Layout verursacht

  • Bereich neu streichen

  • Ob es über kostenintensive Attribute verfügt (CSS-Schatten usw.)

  • Ob die Hardwarebeschleunigung aktiviert werden soll

Das dynamische Ändern des Rands und der Höhe regelmäßiger Flusselemente führt zu einem großflächigen Layoutprozess, der genauso langsam ist wie die Verwendung JS oder CSS3.
Durch die dynamische Änderung des Translate3D des Elements wird auf natürliche Weise die 3D-Beschleunigung aktiviert. Es gibt keinen großen Unterschied in der Bildrate zwischen der Verwendung von setTimeout/setInterval/requestAnimationFrame und CSS3.

Der Hauptunterschied ist heute

1. Die funktionale Abdeckung ist größer als CSS3

  • Die @keyframes, die den Animationsprozess definieren Wenn es mehrere ähnliche Animationsprozesse gibt und mehrere Parameter angepasst werden müssen, um sie zu generieren, gibt es viele Redundanzen (z. B. die Animationslösung von jQuery Mobile), während JS natürlich mehrere Funktionen mit einem Satz implementieren kann von Funktionen. Verschiedene Animationsprozesse

  • Auf der Zeitskala ist die Animationsgranularität von @keyframes grob, während die Animationsgranularitätssteuerung von JS sehr fein sein kann

  • CSS3 In Animationen werden nur sehr wenige Zeitfunktionen unterstützt und sie sind nicht flexibel genug

  • Mit der vorhandenen Schnittstelle kann CSS3-Animation nicht mehr als zwei Zustandsübergänge unterstützen

2. Die Schwierigkeit der Implementierung/Rekonstruktion ist einfacher als bei JS und die Richtung der Leistungsoptimierung ist festgelegt

3. Für Browser mit niedriger Version und schlechter Bildratenleistung , CSS3 kann ein natürliches Downgrade sein, während JS das Schreiben von zusätzlichem Code erfordert

4 CSS3 hat Kompatibilitätsprobleme, aber JS hat meistens keine Kompatibilitätsprobleme


Im Folgenden 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 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.

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; /* 更新 */

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.

Ebenso erfordert die Verwendung von RAF keine große Umgestaltung Ihres Codes. Vergleichen wir den Unterschied zwischen der Verwendung von RAF und der Verwendung von 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);

Sie müssen den Code nur geringfügig ändern, um RAF zu verwenden, und Ihre Animationsleistung wird erheblich verbessert.

CSS Transition

  CSS transition 的动画逻辑是由浏览器来执行,所以它的性能能够比 jQuery 动画好。它的优势体现在:

  1. 通过优化 DOM 操作,避免内存消耗来减少卡顿

  2. 使用与 RAF 类似的机制

  3. 强制使用硬件加速 (通过 GPU 来提高动画性能)

  然而实际上Javascript也可以使用这些优化。GSAP 已经做这些优化很久了。Velocity.js 是一个新兴的动画引擎,它不仅仅做了这些优化,甚至走的更远些。我们稍后会谈到这些。

  面对事实,让 Javascript 动画得以媲美 CSS 动画的性能只是我们伟大计划的第一步。第二步才是重头戏,要让 Javascript 动画比 CSS 动画还要快!

  让我们来看看 CSS 动画库的缺陷吧:

  1. Transition 强制使用了 GPU 的硬件加速。导致浏览器一直处于高负荷运转的状态,这反而会让动画变的卡顿。这在移动浏览器上更为严重。(特别要说明的是,当数据在浏览器的主线程和合成线程之间频繁传输的时候特别消耗性能,故容易导致卡顿。某些 CSS 属性,不会受到影响。Adobe 的博客谈到过这个问题。

  2. IE 10以下的浏览器不支持 transition。而目前 IE8 和 IE9 还是很流行的。

  3. transition 不能完全被 Javascript 控制(只能通过 Javascript 来触发 transition),因为浏览器不知道如何同时让 Javascript 控制动画又同时优化动画的性能。

  反过来说: 基于 Javascript 可以决定什么时候启用硬件加速,它可以支持全版本的 IE,并且它完全可以进行批量动画的优化。

Javascript 动画

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

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

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

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

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

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

  4. 忽略那些变动小到根本看不出来的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 协议。

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

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 绝不仅仅是选择一个正确的动画库。页面上的其他代码也需要优化。


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
Vorheriger Artikel:riot.js lernt [9] RoutingNächster Artikel:riot.js lernt [9] Routing