HOME / BLOG
BLOG

CSS Scroll-driven Animationsの使い方【scroll・view・読了バー】

デフォルト画像

スクロール進捗バーや、要素が画面へ入るタイミングに合わせたアニメーションは、これまでscrollイベントやIntersectionObserverを使って作ることが多いUIでした。CSS Scroll-driven Animationsを使うと、スクロールの進行量をアニメーションのタイムラインとして扱えます。

この記事では、ページ上部の読了進捗バーにscroll()、カードの表示にview()を使います。未対応環境でも本文が消えないようにフォールバックを先に設計します。

時間ではなくスクロール量で動かす

通常のCSSアニメーションは、開始してから何秒経ったかで進みます。Scroll-driven Animationsでは、ページがどこまでスクロールされたか、要素が表示領域のどこまで入ったかを進行度として使います。

2種類のタイムライン

関数基準向いているUI
scroll()スクロールコンテナの進行量読了バー、横移動、背景変化
view()対象要素が表示領域を通過する進行量カード表示、見出し強調、画像変化

完成コード

HTML

<div class="reading-progress" aria-hidden="true"></div>

<main class="article-shell">
  <img class="nines-logo" src="https://kjnine.com/wp-content/themes/kjnines_theme/images/svg2/nines_logo.svg" alt="NINES">
  <header class="hero">
    <p class="eyebrow">SCROLL-DRIVEN ANIMATIONS</p>
    <h1>スクロール量に連動する記事ページ</h1>
    <p>上部の進捗バーと、画面に入るカードの動きをCSSだけで作ります。</p>
  </header>

  <section class="feature-list">
    <article class="feature-card"><span>01</span><h2>scroll()</h2><p>スクロールコンテナの進行量を使います。</p></article>
    <article class="feature-card"><span>02</span><h2>view()</h2><p>要素が表示領域へ入る進行量を使います。</p></article>
    <article class="feature-card"><span>03</span><h2>animation-range</h2><p>動き始めと終わりの範囲を調整します。</p></article>
    <article class="feature-card"><span>04</span><h2>Fallback</h2><p>未対応でも内容は常に読める状態にします。</p></article>
  </section>
</main>

CSS

* {
  box-sizing: border-box;
}

html {
  color: #111;
  background: #f2f5f9;
  font-family: system-ui, sans-serif;
}

body {
  min-height: 220vh;
  margin: 0;
}

.reading-progress {
  position: fixed;
  z-index: 10;
  inset: 0 0 auto;
  height: 5px;
  background: #0057ff;
  transform: scaleX(0);
  transform-origin: left;
  animation: reading-progress linear both;
  animation-timeline: scroll(root block);
  animation-range: 0% 100%;
}

@keyframes reading-progress {
  to {
    transform: scaleX(1);
  }
}

.article-shell {
  position: relative;
  width: min(100% - 32px, 920px);
  margin: 0 auto;
  padding: 80px 0 160px;
}

.nines-logo {
  position: absolute;
  top: 32px;
  right: 0;
  width: 68px;
  opacity: 0.14;
}

.hero {
  min-height: 65vh;
  display: grid;
  align-content: center;
}

.eyebrow,
.feature-card span {
  color: #0057ff;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.14em;
}

.hero h1 {
  max-width: 760px;
  font-size: clamp(2.4rem, 8vw, 5.5rem);
  line-height: 1.05;
}

.feature-list {
  display: grid;
  gap: 28px;
}

.feature-card {
  min-height: 300px;
  display: grid;
  align-content: center;
  padding: clamp(28px, 6vw, 64px);
  border-left: 5px solid #0057ff;
  background: #fff;
  box-shadow: 0 18px 50px rgb(20 35 65 / 8%);
}

@supports (animation-timeline: view()) {
  .feature-card {
    animation: card-in linear both;
    animation-timeline: view();
    animation-range: entry 15% cover 35%;
  }

  @keyframes card-in {
    from {
      opacity: 0;
      transform: translateY(48px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  .reading-progress,
  .feature-card {
    animation: none;
    transform: none;
    opacity: 1;
  }
}

JavaScript

// このデモはCSSだけで動きます。
// 対応確認が必要な場合はCSS.supports()を利用できます。

const supported = CSS.supports('animation-timeline: scroll()');
console.log({ scrollDrivenAnimations: supported });

読了進捗バーを作る

固定した横線へtransform: scaleX(0)を指定し、キーフレームの終点でscaleX(1)にします。animation-timeline: scroll(root block)を指定すると、ルートの縦スクロール量に合わせてバーが伸びます。

カードが画面に入る動きを作る

カードへanimation-timeline: view()を指定すると、カード自身が表示領域を通過する進行量を使えます。animation-range: entry 15% cover 35%で、画面へ入り始めてから十分見える位置までをアニメーション範囲にしています。

animation-rangeを調整する

値の考え方見え方
entry付近から開始要素が画面へ入るタイミングで動く
coverまでに完了要素が見える途中で動きを終えられる
範囲を短くする素早く変化する
範囲を長くするスクロールへゆっくり追従する

フォールバックを先に作る

最も大切なのは、未対応環境でカードが透明のままにならないことです。サンプルでは通常状態を「表示済み」にし、@supports (animation-timeline: view())の中だけでアニメーションを追加しています。新機能を使えなくても内容は読めます。

IntersectionObserverとの使い分け

方法向いていること
Scroll-driven Animationsスクロール進行度に連続して追従する視覚表現
IntersectionObserver表示された瞬間に処理・通信・クラス変更を行う

画像の遅延読み込みや分析イベントなど、JavaScriptの処理を発火したい場合はIntersectionObserverが適しています。見た目をスクロール量へ連動させるだけならCSSを検討できます。

パフォーマンスと使いやすさ

  • transformとopacity中心の軽い動きから始める
  • 多数の大きな要素を同時に動かさない
  • スクロールを奪う演出や極端な視差を避ける
  • prefers-reduced-motionで動きを減らす
  • 低速端末とスマートフォンで実際にスクロールする

CodePen埋め込み用エリア

CSS Scroll-driven Animationsの読了バーとカード表示
ここにCodePenのEmbedコードを貼り付けます。Pen作成後、このブロックと埋め込みタグを差し替えてください。

HTMLとCSSを貼り、ページを縦にスクロールしてください。次にanimation-rangeを変え、カードが動き始める位置と終了位置を比べます。

あわせて読みたい

参考資料

まとめ

CSS Scroll-driven Animationsを使うと、scroll()でページの進行量、view()で要素の表示進行量へアニメーションを連動できます。通常状態では内容を表示し、対応環境だけ動きを追加する設計にすると、安全に段階的な強化ができます。