CSSだけでスクロールアニメーションが作れる!?
新技術Scroll-driven Animationsとは

はてなブックマークへ投稿
71
Xへポスト
URLをコピー
共有

スクロール駆動アニメーション(Scroll-driven Animations)を使うと、スクロール量そのものをアニメーションの進捗に使えます。スクロールと完全に連動して動くスクラブアニメーションや、スティッキーな表現をCSSだけで実装できるのが特徴です。

本記事では、CSSで作るスクロールアニメーションを次の2種類に分けて紹介します。

  • スクロール駆動アニメーション:スクロール量に連動して進む
  • スクロールトリガーアニメーション:スクロール位置をきっかけに、時間で進む

以下は、CSSだけを使って作成したスクロールアニメーションのデモです。一切JavaScriptは使用していません。

スクロール駆動アニメーションの作例

スクロールアニメーションを使うメリットと注意点

スクロールアニメーションには、次のようなメリットがあります。

  • コンテンツの視線誘導に役立つ
  • ウェブサイトの没入感の向上に役立つ

効果的なアニメーションは、優れたユーザー体験を提供する一助となるでしょう。一方、利用者の中にはアニメーションが苦手であったり、画面酔いしやすい方もいます。

スクロールアニメーションが苦手な方のために、モーション軽減設定に配慮した実装も検討するといいでしょう。記事『CSSでもアクセシビリティに配慮しよう! モーション軽減・文字サイズ変更・ダークモードの実装方法』にて解説していますので、ぜひご覧ください。

スクロール駆動アニメーション

スクロール駆動アニメーションでは、連動させるスクロール範囲に応じて、次のタイムラインを使い分けます。

  • スクロール進捗タイムライン(Scroll Progress Timeline):スクロールコンテナー全体の進捗を表す。scroll()関数で指定する
  • ビュー進捗タイムライン(View Progress Timeline):対象要素がスクロールポートを通過する進捗を表す。view()関数で指定する

スクロール進捗タイムライン

スクロール進捗タイムラインは、スクロールコンテナーの先頭から末尾までを0%から100%の進捗として扱います。

次の作例のように、ページのスクロール進捗に連動して、要素が垂直方向にスケールアップするスクラブアニメーションを作ります。

▼左:紹介するデモ、右:アレンジバージョン

ページのスクロールに連動するスクラブアニメーションのデモ

① 事前準備:アニメーションさせる要素(div.animationElement)を用意し、スクロールが発生するようbody要素に適当な高さを確保しておきます。

<div class="animationElement"></div>
body {
  height: 200vh; /* スクロールが発生するよう適当な高さを確保 */
}

@keyframesルールでアニメーションを用意し、アニメーションさせる要素に指定します。

/* 垂直方向にスケールを変えるキーフレーム */
@keyframes grow-progress {
  from {
    scale: 1 0;
  }
  to {
    scale: 1 1;
  }
}

animation-timelineプロパティにscroll()関数を指定します。

.animationElement {
  /* スタイリング */
  position: fixed;
  width: 100px;
  height: 100px;
  background: royalblue;
  transform-origin: bottom; /* 下部を変形の基準にしておく */
  
  /* スクロールアニメーションの設定 */
  animation: grow-progress linear; /* アニメーションを指定。イージングはlinear */
  animation-timeline: scroll();
}

たった数行のCSSで、スクラブアニメーションの完成です。

ビュー進捗タイムライン

ビュー進捗タイムラインは、対象要素がスクロールポートを通過する範囲を0%から100%の進捗として扱います。

続いて、以下の作例のようにスクロールを進めて画面内にアニメーション要素が入ってきた時にマスクが動くスクラブアニメーションを作ります。

ページのスクロールに連動するスクラブアニメーションのデモ

①事前準備:アニメーションさせる要素(div.animationElement)を用意し、スクロールが発生するよう前後に適当な高さを確保した要素(div.skeleton)を配置しておきます。

<div class="skeleton">スクロールを発生させるため適当なエリアを確保しています</div>
<img class="animationElement" src="./images/sapphire.webp" alt="サファイア" width="300" height="300">
<div class="skeleton">スクロールを発生させるため適当なエリアを確保しています</div>
.skeleton {
  height: 100vh; /* スクロールが発生するよう適当な高さを確保 */
}

@keyframesルールでアニメーションを用意し、アニメーションさせる要素に指定します。

今回はマスクを使うアニメーションを作ります。

/* 円→(角丸四角形を経由)→正方形 にマスクの形状を変化させるキーフレーム */
@keyframes reveal-image {
  from {
    clip-path: inset(30% round 20%);
  }
  to {
    clip-path: inset(0);
  }
}

animation-timelineプロパティにview()関数を指定します。

animation-rangeプロパティを設定します。

アニメーションさせる画像がビューポートに完全に入った時点(contain 0%)でアニメーションを開始し、画像がビューポートの真ん中まで来た時(contain 50%)にアニメーションを終了するよう範囲を指定します。

.animationElement {
  /* スクロールアニメーションの設定 */
  animation: reveal-image linear both; /* アニメーションを指定。イージングはlinear。animation-fill-modeはboth */
  animation-timeline: view();
  animation-range: contain 0% contain 50%; /* 開始: 要素がビューポートに完全に入った時、終了: ビューポートの真ん中 */
}

また、animation-rangeプロパティに指定できる値は種類が多く複雑ですので、View Timeline Ranges Visualizerツールが理解の助けになるでしょう。値を変えて試すことができ、わかりやすく視覚化されているのでぜひご活用ください。

animation-range: contain 0% contain 50%;を指定した例

View Timeline Ranges Visualizer

作例:スティッキーとの組み合わせ

ここまで紹介した2種類のタイムラインを使い、スティッキーな表現やパララックスを組み合わせた作例です。物語の一部を用い、没入感が生まれるような装飾とアニメーションを施しました。

▼スクロール駆動アニメーションの作例ページ

スクロール駆動アニメーションの作例

作例中でアニメーションの進捗に使っているのは、スクロール進捗タイムライン(scroll())かビュー進捗タイムライン(view())です。詳しくはサンプルコードをご確認ください。

スクロールトリガーアニメーション

スクロールトリガーアニメーション(Scroll-triggered Animations)は、スクロール位置を再生のきっかけにし、アニメーション自体は通常どおり時間で進める仕組みです。

タイムライントリガーの基本

以下のデモでは、「Animation Item」の文字がビューポートに完全に入ると、右側から1秒かけて表示されます。アニメーションの進捗はスクロール量と連動しないため、スクロールを止めても最後まで再生されます。

/* 右側からフェードインするキーフレーム */
@keyframes motion {
  from {
    opacity: 0;
    translate: 100px 0;
  }
}

.target {
  opacity: 1;
  translate: 0 0;

  /* view()で表示位置を判定。containで有効化し、coverの範囲外で無効化 */
  timeline-trigger: --target view() contain / cover;
  /* 同じクラスの要素ごとにトリガーを分ける */
  trigger-scope: --target;
  /* 通常の時間ベースのアニメーション */
  animation: motion 1s both;
  /* トリガーの有効時は順再生、無効時は逆再生 */
  animation-trigger: --target play-forwards play-backwards;
}

view()は、要素が画面内を通過する位置を判定に使います。containcoverは、その判定範囲を表すキーワードです。この指定では、要素全体が画面内に入るとplay-forwardsで順再生し、完全に画面外へ出るとplay-backwardsで逆再生します。

作例:見出しを1文字ずつ表示する

スクロールトリガーアニメーションは、見出しを1文字ずつ表示する演出にも役立ちます。次の作例では、ブランドサイトなどでよく見かける、見出しの文字がマスクから1文字ずつ現れる演出を、JavaScriptを使わずCSSだけで実装しています。文字を順番に表示することで、上品な印象を与えられます。

同様の表現はGSAPでも実装できます。記事『GSAP入門(第3回) - ScrollTrigger・MotionPath・FLIP・テキストモーション』で紹介していますので、あわせてご覧ください。GSAPを使った実装の利点は、主要なブラウザすべてで動作することです。

対応ブラウザ

スクロール駆動アニメーションで使うanimation-timelineは、Chrome・Edge 115(2023年7月リリース)、Safari 26.0(2025年9月)以上が対応しています。

参照:Can I use…

一方、スクロールトリガーアニメーションで使うanimation-triggerはChrome・Edge 146(2026年3月リリース)以上で利用できます。2026年8月時点では、Safari 26.6・Firefox 154ともに未対応です。

参照:Can I use…

まとめ

CSSだけで作れるスクロール駆動アニメーションとスクロールトリガーアニメーションを紹介しました。作りたいと思ったアニメーションが、手軽に実装できるようになったのではないでしょうか。実装のハードルが下がった分、今後はどのようなアニメーションを作るかが重要になりそうですね!

※この記事が公開されたのは3年前ですが、先月8月に内容をメンテナンスしています。

Google検索でICS MEDIAの記事を見つけやすくしよう

優先するソースに追加すると、GoogleのトップニュースやAI検索でICS MEDIAの記事が表示されやすくなります。

Googleで優先するソースとして追加
SNSでシェアしよう
シェアいただくと、サイト運営の励みになります!
はてなブックマークへ投稿
Xへポスト
URLをコピー
共有
新着記事のお知らせuseStateとuseEffectだけじゃもったいない! ユーザー体験を改善するReactの便利機能