ウェブ アニメーション - element.animate() を Chrome 36 で利用可能に

ウェブ上のアニメーションはかつて JavaScript の領域でしたが、モバイルへの移行に伴い、宣言型構文とブラウザによる最適化を実現するために、アニメーションは CSS に移行しました。モバイルで常に 60 fps を目標としている場合は、ブラウザが効率的に表示できる範囲から外れないことが重要です。

JavaScript 駆動のアニメーションをより効率的にするためのツールが増えていますが、究極の目標は宣言型アニメーションと命令型アニメーションを統合することです。アニメーションの記述方法は、どちらの形式で可能かではなく、最も明確なコードに基づいて決定します。

ウェブ アニメーションがその要望に応え、その最初の部分が element.animate() の形で Chrome 36 に導入されました。この新しい関数を使用すると、アニメーションを純粋に JavaScript で作成し、CSS アニメーションや遷移と同じように効率的に実行できます(実際、Chrome 34 では、これらのすべてのメソッドはまったく同じ Web Animations エンジンによって駆動されます)。

構文はシンプルで、CSS の遷移やアニメーションを記述したことがある人なら、その部分は馴染みがあるはずです。

element.animate([
    {cssProperty: value0},
    {cssProperty: value1},
    {cssProperty: value2},
    //...
], {
    duration: timeInMs,
    iterations: iterationCount,
    delay: delayValue
});

この新機能の最大の利点は、スムーズでぎくしゃくしないアニメーションを実現するために、以前は必要だった面倒な手順を省略できることです。

たとえば、昨年のサンタ トラッカーでは、雪が降り続けるようにしたいと考え、CSS でアニメーション化することで効率的に処理できるようにしました。

ただし、雪の水平位置は、画面とシーン内で発生するイベントに基づいて動的に選択したいと考えました。もちろん、雪が降る高さ(ユーザーのブラウザ ウィンドウの高さ)は、実際に実行されるまでわかりません。そのため、ランタイムで CSS アニメーションを作成するとすぐに複雑になるため(数百個の雪片は数百個の新しいスタイル設定ルールを意味します)、CSS 遷移を使用する必要がありました。

そこで、次のようなアプローチをとりました。

snowFlake.style.transform = 'translate(' + snowLeft + 'px, -100%)';
// wait a frame
snowFlake.offsetWidth;
snowFlake.style.transitionProperty = 'transform';
snowFlake.style.transitionDuration = '1500ms';
snowFlake.style.transform = 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)';

鍵は「フレームを待つ」というコメントにあります。遷移を正常に開始するには、要素が開始位置にあることをブラウザが認識する必要があります。方法はいくつかあります。最も一般的な方法の 1 つは、ブラウザにレイアウトの計算を強制する要素プロパティのいずれかから読み取る方法です。これにより、要素が終点に移行する前に始点があることをブラウザが認識できます。この方法を使用すると、ブラウザ内部の優れた知識を自負しながら、キーを打つたびに罪悪感を感じることができます。

一方、同等の element.animate() 呼び出しは、意図する内容を正確に示しており、非常に明確です。

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);

他にも多くのオプションがあります。CSS のアニメーションと同様に、ウェブ アニメーションは遅らせたり反復したりできます。

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], {
    duration: 1500,
    iterations: 10,
    delay: 300
});

AnimationPlayer

element.animate() は実際には AnimationPlayer オブジェクトを返します。このオブジェクトは、Web Animations 仕様がさらにリリースされるにつれて、ますます重要になります。JavaScript と CSS の両方で作成されたアニメーションには、AnimationPlayer が関連付けられるため、有用で興味深い方法でシームレスに組み合わせることができます。

現時点では、AnimationPlayer には 2 つの機能しかありませんが、どちらも非常に便利です。アニメーションは、AnimationPlayer.cancel() を使用していつでもキャンセルできます。

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
// less than 1500ms later...changed my mind
player.cancel();

また、過去に CSS アニメーションやトランジションを基盤としたアニメーション システムを構築しようとしたことがある人にとっては、ウェブ アニメーションは完了時に常にイベントを発生させるため、安心して使用できます。

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
player.onfinish = function(e) {
    console.log('per aspera ad terra!');
}

試してみる

これらの機能はすべて Chrome 36 でリリースされ、本日ベータ版に移行します。試してみたい場合は、Chrome 36 のネイティブ実装をお試しください。ただし、Web Animations ポリフィルがあり、最新の Evergreen ブラウザに Web Animations 仕様の大部分を導入できます。

雪のエフェクトのデモでは、element.animate()ネイティブ バージョンと ポリフィルの両方を使用できます。

ご意見をお寄せください

ただし、これは今後の機能のプレビューであり、デベロッパーのフィードバックをすぐに収集することを目的としています。すべてのユースケースに対応しているか、アニメーション用の現在の API の粗い部分をすべて削り落としたかは、まだ不明です。デベロッパーの皆様が実際にお試しいただき、ご意見をお聞かせいただくことが、この機能の正確性を確認する唯一の方法です。

この投稿へのコメントはもちろん貴重ですが、標準自体に関するコメントは、public-fx メーリング リストを通じて CSS ワーキング グループと SVG ワーキング グループに送信できます。

更新(2014 年 10 月): Chrome 39 では、play()pause()reverse() など、再生の制御に関連する複数のメソッドがサポートされるようになりました。また、currentTime プロパティを使用して、アニメーションのタイムライン内の特定のポイントにジャンプすることもできます。この機能の動作は、こちらの新しいデモで確認できます。

この投稿に協力してくれた Addy Osmani と Max Heinritz に感謝します。