クリエイターラボ
CSSだけで実装するスクロールアニメーション Scroll-driven Animations
良かったら”♥”を押してね!

目次
はじめに
Javascriptを書かなくてもスクロールアニメーションが実装可能なCSSの機能『Scroll-driven Animations』を今回はご紹介します。
このCSSの機能は今までJavaScriptでスクロールアニメーションを実装していた私からすると結構凄くて、従来の書き方と今回紹介する書き方を比較すると、
■従来↓
JavaScript
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('fade-in');
}
});
});
document.querySelectorAll('.card').forEach(card => {
observer.observe(card);
});
CSS
.card {
opacity: 0;
transform: translateY(50px);
transition: all 0.6s;
}
.card.fade-in {
opacity: 1;
transform: translateY(0);
}
■新しい方法↓
.card {
animation: fade-in linear;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
このように簡単なフェードインアニメーションを実装するだけでも結構な記述量の違いが生まれてきます。従来だとJavaScriptとcssの両方を書かないといけないですからね。
CSSだけで完結するのも管理しやすくてありがたいですね。
必要となるCSSの解説
基本的な実装方法を見ていきましょう。
animation
animation-timeline
animation-range
基本的に必要なCSSはこの3つとなります。
animation
こちらについてはホームページでのcssアニメーションをする際にマストのものなのでご存知の方も多いと思います。
アニメーション名とイージングを設定するものです。アニメーションの名前を任意で決めて、どういう動き方にするか決めるわけですね。
実装例↓
animation: fade-in linear;
因みにイージングの種類は下記の通りです。
ご参考にしてください。
値 | 動き |
linear | 等速(スクロールと同じ速度) |
ease | ゆっくり始まってゆっくり終わる |
ease-in | ゆっくり始まる |
ease-out | ゆっくり終わる |
animation-timeline
ここがCSSスクロールアニメーションの核となります。
何を監視するかをここで決めています。アニメーションの引き金となるものを決めているとも言えると思います。(逆にわかりづらかったらごめんなさい・・・。)
主な使い方は2つあります。
① view()
要素が画面に入ったかを監視しています。
実装例↓
animation-timeline: view();
animation-timeline: view(block 100px 0px);
animation-timeline: view(block 100px 50px);
2行目と3行目の意味としましては
2行目→『要素の上から100px内側のところから監視する。』
3行目→『要素の上から100px内側のところから要素の下から50px内側のところまでを監視する。』
という意味です。ここまで詳細に位置を指定できるのはありがたいですね。簡単なアニメーションであれば本当にJSは要らなそうです。
② scroll()
スクロール量を監視しています。
animation-timeline: scroll(root);
animation-timeline: scroll(nearest);
animation-timeline: scroll(self);
scroll(root) → ページ全体のスクロール量を監視。因みにrootがデフォルト値なので、書かなくて良いです。
scroll(nearest)→ 自分の一個上の階層の親要素のスクロール量。親要素のスクロール量によって自分自身の状態が変わるときに使います。例えばモーダルウインドウ(親)を開いていて、スクロールするごとにプログレスバー(自分自身)が進んだりするときなどに有効ですね。
scroll(self) → 自分自身のスクロール量。その要素自体のスクロール量と言えば良いでしょうか。スクロール量によって自分の背景色を変えるときに使ったりします。
animation-range
最後にanimation-rangeで「いつアニメーションを開始・終了するか」を指定します。 ここでアニメーションのタイミングを細かくコントロールできるわけですね。
実装例↓
animation-range: entry 0% cover 30%;
主なキーワードは下記の通りです↓
キーワード | タイミング |
entry | 要素が画面に入り始めた時 |
exit | 要素が画面から出始めた時 |
cover | 要素が画面を覆っている範囲 |
contain | 要素が画面内に完全に見えている時 |
それぞれ見ていきます。
entry
animation-range: entry 0% entry 100%;
animation-range: entry 0% entry 50%;
1行目 → 『要素が画面に入り始め(0%)たらアニメーションを開始して、完全に入った(100%)らアニメーション終了』
2行目 → 『要素が画面に入り始め(0%)たらアニメーションを開始して、半分まで入った(50%)らアニメーション終了』
といった感じです。
Exit
要素が画面から出始めた時を指します。
animation-range: exit 0% exit 100%;
↑の例で言えば、『要素が画面から出始めて(0%)からアニメーションを開始して、完全に出終わった(100%)タイミングでアニメーション終了』という意味です。
cover
要素が画面と重なっている全期間を指します。イメージとしては、要素が「画面に入り始めてから、完全に出るまでの全体」です。entryとexitのどちらも包括しているような感じですね。
contain
要素が画面内に完全に見えている時を指します。 これは要素が画面の上端から下端まで完全に収まっている状態です。
animation-range: contain 0% contain 100%;
animation-range: contain 20% contain 80%;
1行目 → 『要素が完全に見え始めて(0%)からアニメーションを開始して、完全に見えているところの手前(100%)でアニメーション終了』
2行目 → 『要素が完全に見え始めて20%進んだところからアニメーションを開始して、完全に見え始めて80%進んだところでアニメーション終了』
最初、coverとcontainの違いがわからないと思っていたのですが、
contain → 要素が完全に見えている期間だけ
cover → 要素が画面と重なっている全期間
という認識で良いかと思います。
実践編
ここまで押さえていれば、実践に入って良いと思います。
ここからは実際に使えるアニメーションパターンを紹介していきます。
例①:view() を使ったカードのフェードイン
最頻出と言って良いくらいの要素が画面に入ってきたらふわっと表示されるアニメーションですね。
ポイント↓
animation-timeline: view()で各カードが画面に入ったかを監視して、
animation-range: entry 0% cover 50%で画面に入り始めてから全体の50%まで表示される間アニメーションをしています。
例②:scroll() を使った読了率バー
ページ全体のスクロール量に応じてバーが伸びるプログレスバーです。
ポイント↓
animation-timeline: scroll(root)
でページ全体のスクロール量を監視
スクロール0%でscaleX(0)(バーの幅0%)
スクロール100%でscaleX(1)(バーの幅100%)
最後に
これで以上です。
同じスクロールアニメーションでももっと複雑な動きが求められるようであればまだまだJavaScriptでの記述が必要になるかと思いますが、そこまで複雑でないものであればこのCSSの機能だけで事足りそうです。
使いこなしてホームページ制作の効率化にどんどん繋げていきましょう!

2022年入社。東進ハイスクールの現代文講師林修先生を敬愛してやまないコーダー。林先生に負けないくらいの知的好奇心や探求心を武器にホームページ制作に役立つ有益な情報を発信する。好きな食べ物はいなりです。
この人が書いた記事をもっと見る