Velocity.js CSSを超える最強アニメーションライブラリの秘密に迫る | SiTest (サイテスト) ブログ

メニューボタン閉じるボタン

Velocity.js CSSを超える最強アニメーションライブラリの秘密に迫る

jQueryの登場でアニメーションの表現がとても楽になりました。
更にCSS3がモダンブラウザの全てで動作するようになり、
CSS Transitionsを使った非常に滑らかなアニメーションも実現出来るようになりました。

私はこのCSS Transitionsを使ったアニメーションが最速だと思い続けていたのですが、
どうやらJavaScriptを使った方が速いケースがあるらしいのです。

Webページのアニメーションを行う事に特化したVelocity.jsというライブラリがあります。
なんとこのライブラリを使うだけで、超滑らかなアニメーションが出来るとのこと!
今回は Velocity.js の内部実装を調べながら秘密に迫ってみようと思います。

jQueryアニメーションは何が悪い?

Webサイトでのアニメーションの代名詞とも言えるjQueryアニメーション。
一体何が悪くてカクカクになってしまうのでしょうか?

そこで調べた所、jQueryでは setIntervalsetTimeout を使い、
Velocity.js では requestAnimationFrame を利用しているという情報が得られました。

Verocity.js の実装を確認

実際に Verocity.js のソースコードを確認して、速いと噂の requestAnimationFrame の存在を確認してみましょう。
Verocity.js のソースコードはGitHubで公開されており、誰でもソースコードを閲覧できます。

全てのファイルはverocity.jsに記載されているので、
そこから該当部分の記述をピックアップします。

// L.464:
var rAFShim = (function() {
    var timeLast = 0;

    return window.webkitRequestAnimationFrame
      || window.mozRequestAnimationFrame
      || function(callback) {
        var timeCurrent = (new Date()).getTime(),
            timeDelta;

        /* Dynamically set delay on a per-tick basis to match 60fps. */
        /* Technique by Erik Moller. MIT license: https://gist.github.com/paulirish/1579671 */
        timeDelta = Math.max(0, 16 - (timeCurrent - timeLast));
        timeLast = timeCurrent + timeDelta;

        return setTimeout(function() { callback(timeCurrent + timeDelta); }, timeDelta);
    };
})();
// L.3330:
var ticker = window.requestAnimationFrame || rAFShim;

ベンダープレフィックス付きを含めた requestAnimationFrame を優先的に探し、
もしどうしても見つからない場合は16ms毎にsetTimeoutを加工した自作関数を用意して動かしています。

jQuery の実装を確認

実際にjQueryのソースコードも確認して、setIntervalもしくはsetTimeoutが使われている事を確認してみましょう。
jQueryのソースコードはGitHub上にあり、誰でもソースコードを閲覧できます。

実際にアニメーション関係の記述がある「/src/effects.js」ファイルを閲覧してみることにします。
実際に現行最新版(2016/06時点)では2.2.41.12.4の2種類です。

jQuery.fx.interval = 13;

jQuery.fx.start = function() {
    if ( !timerId ) {
        timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
    }
};

どちらのバージョンでもstart関数はどちらも同じ記述でした。
確かにsetIntervalを利用してアニメーションを実現していました。

ちなみに開発最新版であるmasterブランチの同ファイルを確認した所、
速いと噂のrequestAnimationFrameを優先的に探して利用する記述を見つけました。
近い将来この記述が採用されたライブラリが配布されれば、jQueryのアニメーションもかなり速くなることが期待出来ます。

jQuery.fx.start = function() {
    if ( !timerId ) {
        timerId = window.requestAnimationFrame ?
            window.requestAnimationFrame( raf ) :
            window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
    }
};

setInterval VS requestAnimationFrame

確かに現行版 jQuery は setInterval を採用し、
また Verocity.js も requestAnimationFrame を採用しているようです。

しかし、まだ setInterval が requestAnimationFrame より遅いと決まった訳ではありません。
requestAnimationFrame はそんなに優れているのでしょうか?

……というわけで実験してみました。

velocity-js-1

<form name="controller">
  <label>
    now:
    <input name="now" />
  </label>
</form>
<audio id="audio" controls />

これはaudioとinputの2つのタグだけで作ったシンプルなページです。
現在の音楽の再生箇所の秒数(小数点以下も)をinputタグに逐一反映していきます。

まずは setInterval から見ていきましょう。

velocity-js-setinterval

timeUpdate = function() {
  document.forms.controller.now.value = audio.currentTime;
}
setInterval(timeUpdate, 13);

jQueryのデフォルトと同じ描画頻度の13msに指定しましたが、
秒間約77回もページを書き換える計算になります。

Chromeのタスクマネージャーの機能でCPU使用率も確認しましたが29%と流石の重さです。
数秒間に1度ほんのわずかなタイミングで数字の切り替わりに引っかかるように感じます。

続いて requestAnimationFrame を使った例を見ていきましょう。

velocity-js-requestanimationframe

timeUpdate = function() {
  document.forms.controller.now.value = audio.currentTime;
  requestAnimationFrame(timeUpdate);
}
requestAnimationFrame(timeUpdate);

一切の引っ掛かりも感じません。
CPU使用率も24〜25%付近で止まっています。

setInterval と requestAnimationFrame の結果から考察

Chromeのフレーム切り替えタイミングは秒間約60回である事から、
単純に実行回数の差がCPU使用率に影響しています。
実際に先ほどの例で setInterval の実行感覚を 17ms と設定すると、requestAnimationFrame とほぼ同じCPU使用率となりました。

利用者が変更を感じるのはJavaScriptが画面を書き換えた時ではなく、
あくまでブラウザの再描画のタイミングだったわけです。

これが setInterval と requestAnimationFrame の差として現れているのです。
ブラウザの再描画に合わせて次の処理が走るrequestAnimationFrameは少しだけ効率が良い実装になるのです。
しかし、この少しの差で見た目の滑らかさがこんなに変わるとは思いませんでした。

ちなみにjQueryの再描画タイミングが13ms毎である根拠に関してですが、
古いバージョンのIEやFirefoxはわりと大雑把な実行をしているようです。
書き換え頻度を上げる事で、上記のブラウザに対応したと推測できます。

参考サイト

何故 jQuery は setInterval を使っているのか?

window.requestAnimationFrame – MDN

MDN のサイトにブラウザの実装状況があります。
PC用ブラウザはどれも比較的新しいバージョンでしか動作せず、
スマホ用ブラウザに至ってはベンダープレフィックスなしでは何も動かないという有様です。

またW3Cで勧告された日付も2015/09/22と最近で、
それまでは各ブラウザが先行実装している状態でした。

jQuery は下位互換を重視するライブラリですので、
中々取り入れられない事情があるのでしょうね。

CSS Transitions VS Velocity.js

CSS Transitions は JavaScript 制御のアニメーションと比べると緻密な設定は出来ません。
また、CSS Transitions はGPUを利用できる上、ブラウザネイティブで最適化できるというイメージがありますが、
その効率は現時点では大したアドバンテージではないようです。

Volocity.jsを使ってアニメーションのパフォーマンスを比較してみた – beijaflor

上記サイトのDEMO2では CSS Transitions を扱うライブラリの Transit と、Velocity.js を比較しています。
扱うオブジェクトの数が多すぎる為か、Transit ではアニメーション自体は滑らかなものの、開始直後はフリーズしているように思えます。
CSS Transitions は多数の画像を同期を取りつつ並行して動かす事は苦手なようです。

まとめ

いかがでしたでしょうか?

CSS Transitions も素晴らしい機能ですが、
JavaScriptから扱えるAPIも日々進化している事がわかりました。

HTML5で様々なAPIが増えましたがまだまだ不便との事で、
見えないAPIやそれを扱うライブラリが次々と登場しそうですね。

以上、「CSSを超える最強アニメーションライブラリ!Velocity.jsの秘密に迫る」でした。
最後まで読んでいただきありがとうございました。

今すぐお気軽に
ご相談ください。

0120-315-465

(平日 10:00~19:00)

今すぐお気軽に
ご相談ください。

0120-315-465

(平日 10:00~19:00)

グラッドキューブは
「ISMS認証」を取得しています。

認証範囲:
インターネットマーケティング支援事業、インターネットASPサービスの提供、コンテンツメディア事業

「ISMS認証」とは、財団法人・日本情報処理開発協会が定めた企業の情報情報セキュリティマネジメントシステムの評価制度です。

いますぐ無料で
お試しください。

SiTest の革新的な機能を
お試しいただけます。
利用規約

お名前【必須】
メールアドレス【必須】
電話番号【必須】