Chromium 84 での Web Animations API の改善

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

Kevin Ellis
Kevin Ellis

公開日: 2020 年 5 月 27 日

アニメーションは、正しく使用すると、ブランドの認知度や記憶が高まり、ユーザーのアクションを促して、ユーザーがアプリケーションを操作しやすくなり、デジタル空間にコンテキストがもたらされます。

Web Animations API は、デベロッパーが JavaScript で命令型アニメーションを記述できるツールです。これは、CSS アニメーションと遷移の実装を支え、将来のエフェクトの開発や、既存のエフェクトの作成とタイミングの設定を可能にするために作成されました。

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

2014 年 7 月、Web Animations API は、Chromium のバージョン 36 で初めてヒットしました。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 つ目はマクロ アニメーションで、ページの上部からスライドイン エフェクトとしてプルダウンをメニュー自体の全高分移動させます。2 つ目はマイクロ アニメーションで、下部に達すると少しバウンドします。'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 の今後の予定

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