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

Brendan Kenny 氏
Brendan Kenny

ウェブでのアニメーションは、かつては JavaScript の要領でしたが、世界がモバイルに移行するにつれて、アニメーションは宣言型の構文の CSS に移行され、ブラウザはそれを使用して最適化を実現できるようになりました。モバイルでは常に 60 fps が目標であるため、効率的な表示方法をブラウザが把握している範囲から外れないことが重要です。

JavaScript によるアニメーションの効率を高めるツールが増えているようですが、究極の目標は、宣言型のアニメーションと命令型のアニメーションを統合したものです。つまり、アニメーションの記述方法は、一方の形式では実行できないコードではなく、最も明確なコードに基づいて決定されます。

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

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

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

この新機能の最大のメリットは、スムーズなアニメーションを実現するのに、これまで何度も面倒な作業が必要だった点を排除できることです。

たとえば、昨年のサンタを追いかけようでは、雪が降り続けたいと望んでいましたが、CSS を使ってアニメーション化し、効率よく雪を降らせることにしました。

しかし、画面とシーン自体で発生しているイベントに基づいて、雪の水平位置を動的に選択したいと考えました。もちろん、雪が降る高さ(ユーザーのブラウザ ウィンドウの高さ)は、実際に走るまではわかりませんでした。そのため、CSS Transitions を使用する必要がありました。ランタイム時の 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 つは、ブラウザにレイアウトの計算を強制する要素プロパティの 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 オブジェクトを返しますが、これはウェブ アニメーション仕様がリリースされるにつれて、ますます重要になります。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 ポリフィルという、Web Animations 仕様の大部分を最新のどのブラウザにも適用できます。

雪効果のデモを使用して、ネイティブ バージョンの element.animate()polyfillの両方を使用してみます。

ご意見をお寄せください

実際には、これは今後リリースされる機能のプレビューであり、開発者のフィードバックを即座に取得できるように特別にリリースされています。すべてのユースケースに対応できるのか、それとも現在の API の要点をすべて洗い込んでアニメーション化できているかは、まだわかりません。Google がこの機能を把握して正しく処理するには、デベロッパーがこの機能をお試しいただき、ご意見をお寄せください。

もちろん、この投稿に対するコメントも貴重です。標準に関するコメントは、public-fx メーリング リストを通じて CSS および SVG ワーキング グループまでお送りください。

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

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