この記事の対象: スクロールアニメーションを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 を使う
アニメーションするプロパティはtransformとopacityに限定しましょう。この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())で非対応ブラウザに配慮 - パフォーマンス:
transformとopacityに限定、prefers-reduced-motion対応を忘れずに
CSSで完結するものはCSSで、複雑な表現はGSAP等で——という使い分けが2026年のスタンダードです。
2026年のWebデザイントレンドについては「2026年Webデザイントレンド10選」もあわせてご覧ください。
