CSS によるスクロールトリガーアニメーション
要素が画面内に入った時にアニメーションを開始するスクロールトリガーアニメーションは、これまでは JavaScript を使用して `Intersection Observer API` を利用する方法が一般的でした。JavaScript を使わずに CSS だけで実装を完結できるようになる `animation-trigger` という新しい CSS プロパティが登場しました。
要素が画面内に入った時にアニメーションを開始するスクロールトリガーアニメーションは、ユーザーの注目を集める効果的な方法です。例えば、ユーザーがページをスクロールしてカード要素が画面内に入った時に、カードがフェードインするようなアニメーションを実装できます。これまでは JavaScript を使用して Intersection Observer API を利用する方法が一般的でした。
const cards = document.querySelectorAll(".card");
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
// 要素が画面内に入ったときに entry.isIntersecting が true になる
if (entry.isIntersecting) {
// アニメーションを開始するためのクラスを追加
entry.target.classList.add("animate");
} else {
// 要素が画面外に出たときにクラスを削除(必要に応じて)
entry.target.classList.remove("animate");
}
});
});
// 各要素を監視する
cards.forEach((card) => observer.observe(card));このようなアニメーションは今日の Web サイトで一般的に使用されているアプローチですが、CSS だけで実装を完結できず、ある程度の JavaScript を書く必要があるという課題がありました。この問題を解決するために animation-trigger という新しい CSS プロパティが策定されました。通常の CSS アニメーションは適切な値がセットされている場合にページの読み込み時に開始されますが、animation-trigger プロパティを使用することで、要素が特定の条件を満たすまでアニメーションの開始を遅延したり、トリガーによって一時停止・再開・リセットすることが可能になります。これにより、スクロールトリガーアニメーションを CSS だけで宣言的な方法で実装できるようになります。
この記事では、animation-trigger プロパティを使用してどのようにスクロールトリガーアニメーションを実装できるのかを解説します。animation-trigger は Chrome v146 以降で利用可能です。
animation-trigger プロパティを使用したスクロールトリガーアニメーションの実装
スクロールトリガーアニメーションを実装するために、トリガーを定義します。トリガーを定義するためには timeline-trigger-name と timeline-trigger-source プロパティを使用します。
.card {
timeline-trigger-name: --t;
timeline-trigger-source: view();
}timeline-trigger-name プロパティはトリガーの名前を定義します。ここで定義した名前は後ほど animation-trigger プロパティで参照されます。timeline-trigger-source プロパティはトリガーの条件を定義します。ここでは view() 関数を使用して、要素がビューポート内に入ったときにトリガーが発火するように定義しています。以下のように timeline-trigger-activation-range プロパティで範囲を指定できます。
.card {
timeline-trigger-name: --t;
timeline-trigger-source: view();
timeline-trigger-activation-range: contain 15% contain 85% / entry 100% exit
0%;
}/ の前はトリガーが発火する(要素が入ってくる)方向の範囲、後はトリガーが解除される(要素が出ていく)方向の範囲を表します。
timeline-trigger プロパティで一括して定義できます。
.card {
timeline-trigger: --t view() contain 15% contain 85% / entry 100% exit 0%;
}トリガーを定義したら、あとは animation-trigger プロパティでアニメーションとトリガーを紐づけるだけです。
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.card {
animation-name: fade-in;
animation-duration: 1s;
/* トリガー --t が発火したときにアニメーションを開始する */
animation-trigger: --t play-forwards play-backwards;
/* 名前 --t のスコープをこの要素内とその子孫要素のみに限定する */
trigger-scope: --t;
}play-forwards はトリガーが発火したときにアニメーションを開始することを意味し、play-backwards はトリガーが解除されたときにアニメーションを逆再生することを意味します。他にも以下のような値が利用できます。
| 値 | 説明 |
|---|---|
none |
何も実行しない |
play |
アニメーションを再生する |
play-once |
アニメーションを 1 回だけ再生する(終了後は停止) |
play-forwards |
正の再生速度でアニメーションを再生する |
play-backwards |
負の再生速度でアニメーションを再生する |
pause |
アニメーションを一時停止する |
reset |
アニメーションの進行状況を 0 にリセットする |
replay |
アニメーションの進行状況を 0 にリセットして再生する |
デフォルトでは animation-trigger プロパティで定義した名前はグローバルのスコープに属し、複数の名前が定義された場合は後から定義された名前が優先されます。しかしこの挙動は思わぬバグの原因になる可能性があります。この問題を回避するために
trigger-scope プロパティでスコープを明示的に定義できます。
上記の例では trigger-scope: --t; とすることで、--t という名前のトリガーはこの要素内とその子孫要素のみに適用されるようになります。trigger-scope プロパティは anchor-scope プロパティと同じ設計理念に基づいています。
以下のデモでは、スクロールトリガーアニメーションを実装するための CSS コードの例を示しています。Chrome v146 以降で実行してみてください。
まとめ
- 要素が画面内に入った時にアニメーションを開始するスクロールトリガーアニメーションは、今日の Web サイトで一般的に使用されているアプローチだが、これまでは JavaScript を使用して
Intersection Observer APIを利用する方法が一般的だった animation-triggerという新しい CSS プロパティを使用することで、要素が特定の条件を満たすまでアニメーションの開始を遅延したり、トリガーによって一時停止・再開・リセットすることが可能になり、スクロールトリガーアニメーションを CSS だけで宣言的な方法で実装できるようになるtimeline-trigger-nameとtimeline-trigger-sourceプロパティを使用してトリガーを定義し、animation-triggerプロパティでアニメーションとトリガーを紐づけることでスクロールトリガーアニメーションを実装できるtrigger-scopeプロパティを使用してトリガーのスコープをその要素内とその子孫要素のみに限定することができるanimation-triggerプロパティは Chrome v146 以降で利用可能
参考
- CSS スクロール トリガー アニメーションがまもなく登場します | Blog | Chrome for Developers
- [css-animations-2] Add animation-trigger for triggering animations when an element is in a timeline's range · Issue #8942 · w3c/csswg-drafts
- Animation Triggers
- explainers-by-googlers/scroll-triggered-animations: Explainer for Scroll-Triggered Animations
- [css-animations-2][web-animations-2] How should AnimationTrigger work? · Issue #12119 · w3c/csswg-drafts
- CSS Animations Module Level 2
