💫

Web Animations APIの一番の強みは、擬似要素アニメーションだと思う。

に公開

「JavaScriptで擬似要素をアニメーションさせるのは面倒くさい」

Webサイトのコーディング経験が豊富な方ほど、このように思っているのではないでしょうか。
結論、Web Animations APIを使えば、たったこれだけです!

el.animate([{ opacity: 0 }, { opacity: 1 }], {
  duration: 300,
  pseudoElement: '::before',
});

何を今さら……と呆れ顔で読んでいる方もいらっしゃるかもしれませんが、これを最近知った私はかなり感動したので、まだ知らない人に届けばいいなと思い筆を取りました。

Web Animations APIって?

Web Animations API(以下、WAAPI)は、JavaScriptでDOM要素のアニメーションを実装できるブラウザネイティブのAPIです。

WAAPIは、CSSアニメーションのようなキーフレームベースの記述をJavaScriptから制御可能にするもので、たとえば el.animate() メソッドを使えば、CSSを書かずに動きを付けることができます。アニメーションの再生・停止・逆再生・シークなども、JavaScriptのみで細かく制御できます。

擬似要素のアニメーションは面倒くさい

JavaScriptでのアニメーション実装といえばGSAPを思い浮かべる方も多いと思います。GSAPは大変優れたライブラリで、私も日々の業務で手放せない存在ですが、擬似要素を直接アニメーションさせることはできません。

擬似要素をアニメーションさせたい場合、CSS Variablesを用いた方法が考えられます。

// GSAPを使ってCSS Variablesをアニメーション
gsap.to(element, {
  duration: 0.3,
  '--before-opacity': 0,
});
// SCSSで::beforeにCSS変数を参照させる
.element::before {
  content: '';
  opacity: var(--before-opacity, 1);
}

こういった実装では、DOM上に存在しない擬似要素を間接的に制御するしかなく、スタイルの責務が複雑になります。また、「実際にはアニメーションしてるのはCSSだけど、トリガーはJS」という二段構成にもなりがちで、メンテナンス性にも影響します。

まあ正直、そんなに大変かと言われたらそうでもないのですが、擬似要素を動かすためだけにカスタムプロパティを経由するのはなんだかちょっとやだなーって気がします。ただただ気持ちの問題。

そのため、擬似要素で作成したものをGSAPでアニメーションする必要が出てきた場合、<div>などに置き換えてしまうことも多々ありました。

しかし、そう単純にはいかない場面もあります。

<dialog> 要素の ::backdrop をアニメーションさせたい!

モーダルウィンドウを <dialog> 要素を用いて実装する際、背景のオーバーレイが ::backdrop という擬似要素によって自動的に追加されます。これにフェードトランジションを付け加えたい場合、CSSで実装するとこんな感じ。

dialog::backdrop {  
  opacity: 0;
}
dialog[open]::backdrop {
  animation: fade-in 0.6s forwards;
}
@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

しかし今回は、今後さまざまなプロジェクトで使えるオレオレモーダルライブラリとして発展させる想定でした。簡単なフェードアニメーションくらいであれば、JavaScript Onlyで動くようにしてしまいたいという気持ちがありました。

当然、自動的に挿入される::backdropは生かしつつ、そこにもフェードトランジションを付け加えたい。そう思い、改めて慎重に調べていたところ、WAAPIを使えばいとも簡単に擬似要素をアニメーションさせることが可能とわかりました。

dialog.animate(
  [
    { opacity: 0 },
    { opacity: 1 }
  ],
  {
    duration: 600,
    // 擬似要素を指定
    pseudoElement: '::backdrop'
  }
);

pseudoElement: '::backdrop' を指定するだけ。CSS側での指定は特段不要。JavaScriptで完結。これで動いた時はちょっと感動しました。

まとめ

WAAPIは、軽量でネイティブなアニメーション手段として使いやすく、特に JavaScriptから擬似要素に直接アニメーションをかけられる唯一の手段 という強みがあります。
JavaScriptから擬似要素をアニメーションさせたいケースに直面したら、ぜひ思い出していただければと思います!

Web Animations APIを使ったモーダルライブラリ「Better Dialog」を作りました

Web Animations APIを使って実際にフェードトランジションを実装したモーダルライブラリを公開しました。<dialog>要素を使ってモーダルを実装するときのちょっとした不便を補うことがコンセプトです。

import { BetterDialog } from '@haebaragi/better-dialog';
import { fadeAnimation } from '@haebaragi/better-dialog/animations';

new BetterDialog('#my-dialog', {
  animation: fadeAnimation({ duration: 300 }),
});

興味を持っていただいた方は、ぜひ使ってみてフィードバックをいただけると嬉しいです!

Discussion