テクニック

CSSだけで作るスクロールアニメーション実装ガイド【コピペOK・5パターン】

この記事の対象: スクロールアニメーションをJSなしで実装したいフロントエンドエンジニア・Webデザイナー
読了時間: 約8分

スクロールに連動するアニメーションは、ユーザー体験を大きく向上させる表現技法です。これまではJavaScriptライブラリ(Intersection Observer、GSAP、ScrollTriggerなど)が必須でしたが、2026年現在、CSSだけで多くのスクロールアニメーションが実装可能になっています。

この記事では、CSS Scroll-driven Animationsの基本から、実務で使える5つの実装パターンをコードつきで紹介します。すべてコピペで動作するサンプルです。


CSSスクロールアニメーションの基本

Scroll-driven Animationsとは

CSS Scroll-driven Animationsは、スクロール位置をアニメーションのタイムラインとして使用できるCSS仕様です。従来の@keyframesアニメーションをスクロールに連動させることで、JSなしでスクロールアニメーションを実装できます。

核となる2つのプロパティ:

プロパティ 役割
animation-timeline: scroll() ページ全体のスクロール量に連動
animation-timeline: view() 要素がビューポートに入った位置に連動

scroll()はページ全体の進行率(0%→100%)に基づくアニメーション、view()は個々の要素がビューポートに表示される瞬間をトリガーにするアニメーションです。

ブラウザ対応状況(2026年3月時点)

ブラウザ 対応状況
Chrome 115以降で対応(安定版)
Edge 115以降で対応
Safari 18以降で対応(2024年秋〜)
Firefox 実験的サポート(フラグ有効化が必要)

主要ブラウザの約90%以上をカバーしており、プロダクション環境での使用が十分に現実的です。Firefoxのフル対応が課題ですが、後述するフォールバック手法で対応可能です。

従来のJSとの違い

項目 CSS Scroll-driven JS(Intersection Observer等)
パフォーマンス メインスレッド不要で高速 JSの実行コストあり
実装量 CSSのみで完結 HTML + CSS + JS
細かい制御 限定的 自由度が高い
ブラウザ対応 2026年時点で約90% ほぼ100%

CSSの最大の利点はパフォーマンスです。ブラウザのコンポジタースレッドで処理されるため、メインスレッドをブロックせず、60fpsのスムーズなアニメーションが実現できます。


実装パターン5選(各コード付き)

パターン1: フェードイン(スクロールで要素が現れる)

最も基本的なパターン。要素がビューポートに入ったときに、透明→不透明にフェードインします。

<div class="fade-in">
  <p>スクロールすると表示されます</p>
</div>
.fade-in {
  animation: fadeIn linear both;
  animation-timeline: view();
  animation-range: entry 0% entry 100%;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

解説:
animation-timeline: view() — 要素がビューポートに入るタイミングに連動
animation-range: entry 0% entry 100% — 要素の上端がビューポート下端に達した時点(0%)から完全に表示された時点(100%)までの間でアニメーション

パターン2: スライドイン(左右から要素が入る)

カードやセクションが画面の左右からスライドしてくるパターン。ポートフォリオや事例紹介で効果的です。

.slide-in-left {
  animation: slideInLeft linear both;
  animation-timeline: view();
  animation-range: entry 0% entry 80%;
}

.slide-in-right {
  animation: slideInRight linear both;
  animation-timeline: view();
  animation-range: entry 0% entry 80%;
}

@keyframes slideInLeft {
  from {
    opacity: 0;
    transform: translateX(-60px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes slideInRight {
  from {
    opacity: 0;
    transform: translateX(60px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

ポイント: translateXの値は40〜80pxが自然な印象。100px以上だと動きが大きすぎて違和感が出ます。animation-rangeの終点を80%にすることで、要素が完全に見える前にアニメーションが完了し、ユーザーがストレスなく読み始められます。

パターン3: スケールアップ(画像が拡大して現れる)

画像やカードが小さい状態から通常サイズに拡大するパターン。ギャラリーや商品一覧で使うと印象的です。

.scale-up {
  animation: scaleUp linear both;
  animation-timeline: view();
  animation-range: entry 0% entry 100%;
}

@keyframes scaleUp {
  from {
    opacity: 0;
    transform: scale(0.8);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

ポイント: scale()の初期値は0.8〜0.9がおすすめ。0.5以下にすると「急に出てくる」感じが強くなり、UIが不安定に見えます。

パターン4: パララックス風背景(奥行き感の演出)

背景画像をスクロール速度と差をつけて動かすパララックス効果。セクション背景で使うと立体感が生まれます。

.parallax-section {
  position: relative;
  overflow: hidden;
  height: 60vh;
}

.parallax-section::before {
  content: '';
  position: absolute;
  inset: -20% 0;
  background: url('background.jpg') center / cover no-repeat;
  animation: parallax linear both;
  animation-timeline: scroll();
}

@keyframes parallax {
  from {
    transform: translateY(-10%);
  }
  to {
    transform: translateY(10%);
  }
}

解説:
animation-timeline: scroll() — ページ全体のスクロールに連動(view()ではない点に注意)
inset: -20% 0 — 背景を上下に20%拡張し、移動時に隙間が見えないようにする
translateYの移動量は控えめに。±10%程度が自然

パターン5: プログレスバー(読了率表示)

記事の読了率をページ上部にバーで表示するパターン。ブログやメディアサイトで定番です。

.progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: #0066ff;
  transform-origin: left;
  animation: progressBar linear;
  animation-timeline: scroll();
  z-index: 9999;
}

@keyframes progressBar {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

ポイント: scaleXを使う理由はwidthのアニメーションよりパフォーマンスが高いため。transformはコンポジタースレッドで処理され、リペイントが発生しません。


フォールバック対応

Firefoxや古いブラウザに対応するため、@supportsを使ったフォールバックを設定しましょう。

/* フォールバック: アニメーションなしで通常表示 */
.fade-in {
  opacity: 1;
  transform: translateY(0);
}

/* Scroll-driven Animations対応ブラウザのみ */
@supports (animation-timeline: view()) {
  .fade-in {
    animation: fadeIn linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 100%;
  }
}

この方法であれば、非対応ブラウザでは要素が最初から表示された状態になり、コンテンツが隠れたままになる問題を防げます。


JSライブラリとの使い分け

CSSだけでは難しいケースもあります。用途に応じてJSライブラリを使い分けましょう。

やりたいこと CSS JS推奨
フェードイン / スライドイン
プログレスバー
パララックス(基本)
スクロールに応じた数値カウントアップ ✅(GSAP)
ピン留め(sticky scroll) ✅(ScrollTrigger)
複雑なシーケンスアニメーション ✅(GSAP Timeline)
テキストの1文字ずつ出現 ✅(SplitText等)

GSAPとScrollTriggerは、CSSでカバーできない複雑なアニメーションに最適です。CSSで十分な表現はCSSで、JSが必要な表現だけJSで——というハイブリッドアプローチが現在のベストプラクティスです。

GSAPの入門については「GSAP アニメーション入門」で解説予定です。


パフォーマンスの注意点

transform と opacity を使う

アニメーションするプロパティはtransformopacityに限定しましょう。この2つはコンポジタースレッドで処理されるため、メインスレッドをブロックしません。

避けるべきプロパティ:
width / height(レイアウト再計算が発生)
margin / padding(同上)
top / left(レイアウトシフトの原因)
box-shadow(リペイントが重い)

will-change は控えめに

will-change: transformを多用すると、ブラウザがGPUレイヤーを大量に作成し、逆にメモリを圧迫します。本当に必要な要素にのみ使いましょう。

prefers-reduced-motion に対応する

アクセシビリティの観点から、動きを減らす設定のユーザーにはアニメーションを無効化します。

@media (prefers-reduced-motion: reduce) {
  .fade-in,
  .slide-in-left,
  .slide-in-right,
  .scale-up {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

これは単なるベストプラクティスではなく、アクセシビリティ基準(WCAG 2.1 レベルAA)の要件です。


まとめ

CSS Scroll-driven Animationsによって、多くのスクロールアニメーションがJSなし・CSSだけで実装できるようになりました。

  • 基本: animation-timeline: view()(要素表示連動)と scroll()(ページスクロール連動)の2種類
  • 実装パターン: フェードイン、スライドイン、スケールアップ、パララックス、プログレスバー
  • フォールバック: @supports (animation-timeline: view())で非対応ブラウザに配慮
  • パフォーマンス: transformopacityに限定、prefers-reduced-motion対応を忘れずに

CSSで完結するものはCSSで、複雑な表現はGSAP等で——という使い分けが2026年のスタンダードです。

2026年のWebデザイントレンドについては「2026年Webデザイントレンド10選」もあわせてご覧ください。