Chromium 84 での Web Animations API の改善

プロミスによるアニメーションのオケストレーション、交換可能なアニメーションによるパフォーマンスの向上、合成モードによるアニメーションの滑らかさの向上など。

公開日: 2020 年 5 月 27 日

アニメーションを正しく使用すると、ブランドのユーザー コンバージョンと記憶を高め、ユーザー アクションをガイドし、ユーザーがアプリを操作するのをサポートして、デジタル空間のコンテキストを提供できます。

Web Animations API は、デベロッパーが JavaScript で命令型アニメーションを記述できるツールです。この API は、CSS アニメーションと遷移の両方の実装を支え、今後の効果の開発を可能にし、既存の効果を合成してタイミングを設定できるようにするために作成されました。

FirefoxSafari では、仕様の機能のセット全体がすでに実装されていますが、Chromium 84 では、これまでサポートされていなかった多くの機能が Chrome と Edge に導入され、クロスブラウザの相互運用性が実現されています。

Web Animations API は、2014 年 7 月のバージョン 36 で初めて Chromium に導入されました。2020 年 7 月にリリースされるバージョン 84 で、この仕様は完成する予定です。
Chromium における Web Animations API の長い歴史。

スタートガイド

@keyframe ルールを使用したことがある場合は、Web Animations API を使用してアニメーションを作成する方法に慣れているはずです。まず、Keyframe オブジェクトを作成する必要があります。CSS では次のように記述します。

@keyframes openAnimation {
  0% {
    transform: scale(0);
  }
  100% {
    transform: scale(1);
  }
}

は JavaScript では次のようになります。

const openAnimation = [
  { transform: 'scale(0)' },
  { transform: 'scale(1)' },
];

CSS でアニメーションのパラメータを設定する場所:

.modal {
  animation: openAnimation 1s 1 ease-in;
}

JS で次のように設定します。

document.querySelector('.modal').animate(
    openAnimation, {
      duration: 1000, // 1s
      iterations: 1, // single iteration
      easing: 'ease-in' // easing function
    }
);

コード量はほぼ同じですが、JavaScript を使用すると、CSS だけではできないいくつかの高度な機能が利用できます。これには、エフェクトのシーケンス設定や、再生状態の細かい制御が含まれます。

element.animate()

ただし、今回の更新により、Web Animations API は element.animate() を使用して作成されたアニメーションに限定されなくなりました。CSS のアニメーションや遷移も操作できます。

getAnimations() は、element.animate() を使用して作成されたか、CSS ルール(CSS アニメーションまたは遷移)を使用して作成されたかにかかわらず、要素上のすべてのアニメーションを返すメソッドです。例を次に示します。

まず、遷移のキーフレームを "get" して、遷移元を決定します。次に、2 つの新しい不透明度アニメーションを作成し、クロスフェード エフェクトを有効にします。クロスフェードが完了したら、コピーを削除します。

Promise を使用してアニメーションをオーケストレートする方法

Chromium 84 では、Promise で使用できるメソッドが animation.readyanimation.finished の 2 つになりました。

  • animation.ready を使用すると、保留中の変更が有効になるまで待機できます(再生と一時停止などの再生操作方法を切り替える)。
  • animation.finished は、アニメーションが完了したときにカスタム JavaScript コードを実行する手段を提供します。

例を続け、animation.finished を使用してオーケストレートされたアニメーション チェーンを作成します。ここでは、垂直変換(scaleY)の後に水平変換(scaleX)が続き、子要素の不透明度が変更されます。

開くモーダル要素に変換と不透明度を適用しています。Codepen でデモを確認する
const transformAnimation = modal.animate(openModal, openModalSettings);
transformAnimation.finished.then(() => { text.animate(fadeIn, fadeInSettings)});

チェーン内の次のアニメーション セットを実行する前に、animation.finished.then() を使用してこれらのアニメーションを連結しています。これにより、アニメーションが順番に表示され、異なるターゲット要素に異なるオプション(速度やイージーなど)を設定して効果を適用することもできます。

CSS では、特に複数の要素にユニークでシーケンス化されたアニメーションを適用する場合、この再現は煩雑になります。@keyframe を使用して、アニメーションを配置する正しいタイミングの割合を整理し、シーケンス内のアニメーションをトリガーする前に animation-delay を使用する必要があります。

例: 再生、一時停止、巻き戻し

開くことができるものは、閉じることができるはずです。幸い、Chromium 39 以降、Web Animations API でアニメーションの再生、一時停止、巻き戻しができるようになりました。

.reverse() を使用してボタンをもう一度クリックすると、前に表示されたアニメーションをスムーズに逆再生できます。これにより、モーダルの操作がよりスムーズになり、コンテキストに沿った操作が可能になります。

ボタンのクリックでモーダルが開閉する例。Glitch でデモを見る

2 つの再生保留中のアニメーション(openModal とインライン不透明度変換)を作成し、一方のアニメーションを一時停止して、もう一方のアニメーションが完了するまで遅らせることができます。その後、プロミスを使用して、各処理が完了するのを待ってから再生できます。最後に、フラグが設定されているかどうかを確認し、各アニメーションを逆再生します。

例: 部分的なキーフレームを使用した動的インタラクション

リターゲティングの例。マウスクリックでアニメーションを新しい位置に調整します。Glitch でデモを見る
selector.animate([{transform: `translate(${x}px, ${y}px)`}],
    {duration: 1000, fill: 'forwards'});

この例では、キーフレームは 1 つだけで、開始位置は指定されていません。これは、部分的なキーフレームを使用する例です。マウス ハンドラは、新しい終了位置を設定し、新しいアニメーションをトリガーします。新しい開始位置は、現在の元の位置から推測されます。

既存の切り替えが実行されている間に、新しい切り替えをトリガーできます。つまり、現在の遷移が中断され、新しい遷移が作成されます。

交換可能なアニメーションによるパフォーマンスの向上

'mousemove' などのイベントに基づいてアニメーションを作成すると、毎回新しいアニメーションが作成されるため、メモリが急速に消費され、パフォーマンスが低下する可能性があります。この問題に対処するため、Chromium 83 で交換可能なアニメーションが導入され、自動クリーンアップが可能になりました。これにより、終了したアニメーションは交換可能としてフラグが付けられ、別の終了したアニメーションに置き換えられた場合は自動的に削除されます。たとえば次のようになります。

マウスを動かすと彗星の尾がアニメーション化されます。Glitch でデモを見る
elem.addEventListener('mousemove', evt => {
  rectangle.animate(
    { transform: translate(${evt.clientX}px, ${evt.clientY}px) },
    { duration: 500, fill: 'forwards' }
  );
});

マウスを動かすたびに、ブラウザは彗星の尾の各ボールの位置を再計算し、この新しいポイントへのアニメーションを作成します。次の場合、ブラウザは古いアニメーションを削除(置き換えを有効化)できるようになりました。

  1. アニメーションが完了します。
  2. コンポジションの順序で上位にある 1 つ以上のアニメーションも完了している。
  3. 新しいアニメーションでアニメーション化されるプロパティが同じである。

anim.onremove を使用してカウンタをトリガーし、削除されたアニメーションごとにカウンタを加算することで、置き換えられているアニメーションの数を正確に確認できます。

アニメーションの制御をさらに細かく行うには、次のプロパティとメソッドを使用します。

  • animation.replaceState は、アニメーションがアクティブか、保持されているか、削除されたかをトラッキングする手段を提供します。
  • animation.commitStyles() は、基盤となるスタイルに基づいて要素のスタイルを更新し、要素のすべてのアニメーションを複合順序で更新します。
  • animation.persist() は、アニメーションを交換不可としてマークします。

合成モードによるスムーズなアニメーション

Web Animations API を使用すると、アニメーションの合成モードを設定できるようになりました。つまり、デフォルトのモードである「置換」に加えて、加算モードまたは累積モードを指定できます。合成モードを使用すると、デベロッパーは個別のアニメーションを記述し、エフェクトの組み合わせを制御できます。'replace'(デフォルト モード)、'add''accumulate' の 3 つの複合モードがサポートされるようになりました。

アニメーションを合成すると、デベロッパーは短い個別のエフェクトを記述し、それらを組み合わせて確認できます。次の例では、各ボックスに回転とスケールのキーフレームを適用しています。調整は、オプションとして追加された合成モードのみです。

デフォルト、加算、累積の合成モードを示すデモ。Glitch でデモを見る

デフォルトの 'replace' コンポジット モードでは、最終的なアニメーションが変換プロパティに置き換えられ、rotate(360deg) scale(1.4) で終了します。'add' の場合、合成は回転を追加してスケールを乗算し、最終状態 rotate(720deg) scale(1.96) になります。'accumulate' は変換を組み合わせて rotate(720deg) scale(1.8) を生成します。これらの複合モードの詳細については、Web アニメーションの仕様で CompositeOperation 列挙型と CompositeOperationOrAuto 列挙型をご覧ください。

次の UI 要素の例をご覧ください。

2 つの合成アニメーションが適用された弾むプルダウン メニュー。Glitch でデモを見る

ここでは、2 つの top アニメーションが合成されています。1 つはマクロ アニメーションで、ページの上部からスライドイン エフェクトとしてプルダウンをメニュー自体の全高分移動させます。もう 1 つはマイクロ アニメーションで、下部に達したときに少しバウンスします。'add' 複合モードを使用すると、よりスムーズな遷移が可能になります。

const dropDown = menu.animate(
    [
      { top: `${-menuHeight}px`, easing: 'ease-in' },
      { top: 0 }
    ], { duration: 300, fill: 'forwards' });

  dropDown.finished.then(() => {
    const bounce = menu.animate(
      [
        { top: '0px', easing: 'ease-in' },
        { top: '10px', easing: 'ease-out' },
        { ... }
      ], { duration: 300, composite: 'add' });
  });

Web Animations API の今後の予定

これらは、現在のブラウザのアニメーション機能に追加された新機能です。今後もさらに追加される予定です。今後の予定について詳しくは、以下の将来の仕様をご覧ください。