[CSS]スクロール駆動アニメーションの作り方と実装例3種

2026年10月27日に Firefox 159 がリリースされ、主要ブラウザのすべてがスクロール駆動アニメーションに対応しました。そこで、基本的な作り方と実装例3種を紹介します。

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

CSS のアニメーションは、@keyframes で設定した from (0%) から to (100%) のキーフレームアニメーションを、時間で再生していました。0秒の from の状態から5秒後に to の状態になるといったアニメーションです。

対して、スクロール駆動アニメーションは、特定の要素のスクロールが「始まったとき」「終わったとき」、または、特定の要素がスクロールによって「画面内に入ったとき」「画面外に出たとき」のように、スクロール時の状態によって from の状態から to の状態になるアニメーションです。

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

スクロール駆動アニメーションを作るには、タイムライン (アニメーションの時間軸) を作成する必要があります。タイムラインは特定の要素のスクロール量と可視状態の2種類から作成できます。

スクロール量からタイムラインを作成する

html {
  scroll-timeline-name: --timeline;
  scroll-timeline-axis: block; /* block, inline, x, y が設定できる */
  /* ショートハンド
  scroll-timeline: --timeline block;
  */
}

スクロールが「始まったとき」から「終わったとき」のスクロール量を取得したい要素に、名前 (scroll-timeline-name)、スクロール方向 (scroll-timeline-axis) を設定します。上記の例では、html 要素 (ページ全体) のブロック方向のスクロール量でタイムラインを作成します。

可視状態からタイムラインを作成する

div {
  view-timeline-name: --timeline;
  view-timeline-axis: block; /* block, inline, x, y が設定できる */
  view-timeline-inset: 0;
  /* ショートハンド
  view-timeline: --timeline block 0;
  */
}

スクロールによって「画面内に入ったとき」から「画面外に出たとき」の可視状態を取得したい要素に、名前 (view-timeline-name)、スクロール方向 (view-timeline-axis)、アニメーションの開始位置と終了位置を調整するインセット値 (view-timeline-inset) を設定します。

作成したタイムラインをアニメーションに適用する

@keyframes div-animation {
  from { … }
  to { … }
}
div {
  animation-name: div-animation;
  animation-duration: 1ms; /* Firefox bugfix */
  animation-timing-function: linear;
  animation-fill-mode: both;
  /* ショートハンド
  animation: div-animation 1ms linear both;
  */

  animation-timeline: --timeline;

  animation-range-start: 0%;
  animation-range-end: 100%;
  /* ショートハンド
  animation-range: 0% 100%;
  */
}

@keyframes でアニメーションの内容を設定して、 アニメーションさせたい要素に各種プロパティを設定します。

通常は animation-duration プロパティで再生時間、animation-delay プロパティで遅延時間を設定しますが、スクロール駆動アニメーションでは animation-timeline プロパティで特定の要素のタイムラインを割り当てて、animation-range プロパティでアニメーションに使用するタイムラインの範囲を設定します。

Firefox には animation-duration プロパティが初期値の 0s (0秒) のとき、スクロール駆動アニメーションが動作しなくなる不具合があったようなので、念のため 1ms (1マイクロ秒) を設定しています。

より詳しい情報を知りたい場合は、MDN の各種ページをご覧ください。

実装例その1: パララックス (視差効果)

See the Pen CSS Parallax using scroll-timeline property by nov (@numerofive) on CodePen.

近くのものほど動きが速く、遠くのものほど動きが遅くなる、そのズレを再現できます。以前紹介した position: sticky; を使用した紙芝居のようなパララックス とは異なります。

html 要素 (ページ全体) のスクロール量を取得し、背面に配置した SVG 画像の位置と移動量を設定しています。近くのものほど移動量を多くし (from { transform: translateY(0); } to { transform: translateY(-60svh); })、遠くのものほど移動量を少なく (from { transform: translateY(0); } to { transform: translateY(-10svh); }) 設定しています。

実装例その2: 蛇行スクロール

See the Pen Bidirectional scroll using scroll-timeline property by nov (@numerofive) on CodePen.

縦方向にスクロールしていくと、途中で横方向のスクロールになり、再び縦方向のスクロールに戻るというものです。

<div class="panels" style="--panels: 2;">
  <section class="panel"> … </section>
  <section class="panel"> … </section>
</div>
<div class="panels reverse" style="--panels: 3;">
  <section class="panel"> … </section>
  <section class="panel"> … </section>
  <section class="panel"> … </section>
</div>
<div class="panels" style="--panels: 2;">
  <section class="panel"> … </section>
  <section class="panel"> … </section>
</div>

仕組みとしては、パネル (section.panel) は画面と同じ高さを持っており粘着する設定 (min-block-size: 100svb; position: sticky; inset-block-start: 0;) になっています。その親要素のパネルグループ (div.panels) はパネルの高さとパネルの数を掛けた高さ (min-block-size: calc(100svb * var(--panels));) と view-timeline プロパティが設定してあります。

div.panels の高さがタイムラインになっており、パネルの数だけ縦にスクロールする間に、アニメーションによってパネルが横に移動するという仕組みになっています。通常であれば、パネルが表示されない区間ができますが、スクロールに粘着しているため、常にパネルが表示される状態になります。

実装例その3: スクロールする表のスクロールヒント

See the Pen Scrollable table with scroll hints using scroll-timeline property by nov (@numerofive) on CodePen.

 これは以前も紹介したことがあるのですが、改めて紹介します。スクロール可能な表にスクロールできることをアピールするスクロールヒントを表示するというものです。

<div class="scrollable-table">
  <::before />
  <table> … </table>
  <::after />
</div>

::after 擬似要素、::before 擬似要素、table 要素がグリッドレイアウトによって3層重なっています。

::after 擬似要素には右向き矢印が設定されており、スクロールの先頭1pxが表示領域入っている場合に表示されます。

::before 擬似要素には左向き矢印が設定されており、スクロールの末尾1pxが表示領域入っている場合に表示されます。

表示領域が広い場合、スクロールする必要がない状態になりますが、この場合、スクロール駆動アニメーションは適用されなくなるため、矢印も表示されなくなります。

〆

CodePen で載せた実装例は Codex でベースを作りました。AI に頼めば、それらしいものを作ってくれますが、実際に、何がどのように機能しているか、要素を増減させたときにも対応できるかどうかなど、実際に手を動かして色々と試してみるのって重要だと思いました。

関連記事