ホームページ  >  記事  >  ウェブフロントエンド  >  CSS アニメーションと JavaScript アニメーションの比較

CSS アニメーションと JavaScript アニメーションの比較

伊谢尔伦
伊谢尔伦オリジナル
2017-01-16 16:37:561351ブラウズ

CSS3 アニメーションの利点:

  • パフォーマンスがわずかに向上し、ブラウザーは CSS3 アニメーション用にいくつかの最適化を行います (アニメーションを実行するためだけに新しいレイヤーを作成するなど)

  • コードは比較的シンプルです

しかし、欠点も明らかです:

  • アニメーション制御の柔軟性が十分ではない

  • 互換性が低い

一部のアニメーション機能(スクロールアニメーション、視差スクロールなど)を実装できません

JavaScriptアニメーション これら 2 つの欠点を補っており、単一フレームの制御と変換が可能であると同時に、IE6 と完全に互換性があり、強力な機能を備えています。ただし、CSS アニメーションの変換行列は C++ レベルの計算であるため、JavaScript レベルの計算よりも高速でなければならないことを考慮してください。さらに、ライブラリへの依存も頭痛の種です。

一部の複雑な制御されたアニメーションの場合は、JavaScript を使用する方がより信頼性が高くなります。いくつかの小さなインタラクティブ効果を実装する場合は、より多くの CSS を考慮してください。

同じコンテキストでの実際のプロジェクトの経験という点では、2 つのソリューション間でアニメーションの効率に大きな違いはありません。より効率に影響を与えるのは、

  • レイアウトの領域が発生するかどうかです。

  • 再描画

  • 高コストの属性(CSSシャドウなど)がある

  • ハードウェアアクセラレーションが有効かどうか

通常のフロー要素のマージンと高さを動的に変更すると、大幅な- エリアレイアウトプロセス。JS または CSS3 を使用するのと同じくらい時間がかかります。

要素のtranslate3Dを動的に変更すると、当然3Dアクセラレーションが有効になります。 setTimeout/setInterval/requestAnimationFrameを使用する場合とCSS3を使用する場合とで、フレームレートに大きな違いはありません。

今日の主な違いは

1. 関数のカバレッジが CSS3 よりも大きい


  • アニメーション処理を定義する @keyframes は、類似したアニメーション処理が複数ある場合、複数のパラメータが必要です。調整されたものが生成されると、多くの冗長性 (jQuery Mobile のアニメーション ソリューションなど) が存在し、JS は一連の関数で複数の異なるアニメーション処理を自然に実装できます

  • 時間スケールでは、@ のアニメーション粒度キーフレームは大まかですが、JS のアニメーション粒度制御は非常に細かくできます

  • CSS3 アニメーションでサポートされている時間関数は非常に少なく、十分な柔軟性がありません

  • 既存のインターフェイスでは、CSS3 アニメーションは 2 つ以上をサポートできません状態遷移

2. CSS3 は JS よりも簡単であり、パフォーマンス調整の方向性が固定されています

3. フレーム レートのパフォーマンスが低い低バージョンのブラウザでは、CSS3 は自然に低下する可能性があります。 JS 追加のコードを記述する必要があります

4. CSS3 には互換性の問題がありますが、JS にはほとんどの場合互換性の問題がありません


以下では、JavaScript ベースの DOM アニメーション ライブラリ (たとえば、 Velocity.js および GSAP) は、jQuery および CSS ベースのアニメーション ライブラリよりも効率的です。

jQuery

基本的なことから始めましょう: Javascript と jQuery は混在しません。 Javascript アニメーションは高速ですが、jQuery アニメーションは低速です。なぜ? jQuery は非常に強力ですが、その設計目標は効率的なアニメーション エンジンになることではありません:

  • jQuery はレイアウト スラッシングを避けることができません (これを「レイアウト スラッシング」と翻訳することを好む人もいますが、これは冗長な再レイアウト/リフローにつながります)。このコードはアニメーションに使用されるだけでなく、他の多くのシナリオでも使用されるからです。

  • jQuery は大量のメモリを消費し、ガベージ コレクションを頻繁にトリガーします。ガベージ コレクションがトリガーされると、アニメーションが停止しやすくなります。

  • jQuery は reqeustAnimationFrame(RAF) の代わりに setInterval を使用します。これは、ウィンドウがフォーカスを失うと RAF が起動を停止し、jQuery のバグが発生するためです。 (現在、jQuery はすでに RAF を使用しています)

レイアウトのスラッシングによりアニメーションが最初にフリーズし、ガベージ コレクションのトリガーにより実行中のプロセス中にアニメーションがフリーズすることに注意してください。RAF を使用しないとアニメーション フレームが発生します。率が低いこと。

実装例

レイアウトのスラッシングを避けるために、DOMにバッチでアクセスして更新する必要があります。

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

更新操作後のアクセス操作では、ブラウザーにページ要素のスタイルの再計算が強制されます (正しい値を取得するには、更新されたスタイルを適用する必要があるため)。これにより、通常の操作では大きなパフォーマンスの低下は発生しませんが、わずか 16 ミリ秒の間隔のアニメーションに配置すると、重大なパフォーマンスのオーバーヘッドが発生します。操作の順序を少し変更するだけで、アニメーションのパフォーマンスが大幅に向上します。

同様に、RAF を使用すると、コードを大幅にリファクタリングする必要はありません。 RAF を使用する場合と 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);

RAF を使用するにはコードを少し変更するだけで、アニメーションのパフォーマンスが大幅に向上します。

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


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。