markdown
はじめに (対象読者・この記事でわかること)
この記事は、Web フロントエンドの開発に興味があるエンジニアや、実務で UI を改善したいと考えている JavaScript 初学者・中級者を対象としています。
この記事を読むことで、スクロールに連動した「ふわっと」フェードイン・スライドインアニメーションの仕組みが理解でき、純粋な JavaScript と CSS だけで実装できるようになります。実装例をコピー&ペーストすれば、すぐに自分のサイトに取り入れられます。背景にある「Intersection Observer API」の役割や、アニメーションをスムーズにするトリックも併せて学べます。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- 基本的な HTML / CSS の記述ができること
- JavaScript の変数・関数定義が理解できていること
背景と「ふわっと」スクロールアニメーションの概要
Web ページに長いコンテンツが続くと、ユーザーは自然にスクロールしながら情報を追っていきます。このとき、要素が突然現れるのではなく、スクロール位置に合わせて「ふわっと」出現させると、視覚的に心地よく、ページ全体の一貫性が高まります。
近年、軽量でパフォーマンスに優れた Intersection Observer API がブラウザに標準実装され、スクロールイベントのハンドリングを従来の scroll リスナーよりも効率的に行えるようになりました。この API は、対象要素がビューポート(または指定したルート)に交差した瞬間を検知し、コールバックを呼び出すだけなので、レイアウトスラッシングを防げます。
本稿では、以下の流れで実装を解説します。
- HTML の構造と CSS でアニメーション用クラスを用意
- JavaScript で Intersection Observer を設定し、要素が可視領域に入ったらクラスを付与
- アニメーションのカスタマイズ(遅延、イージング、方向)とパフォーマンス最適化
この手順を踏めば、ページ全体に統一感のある「ふわっと」エフェクトを簡単に実装できます。
具体的な手順と実装方法
ステップ1:HTML と CSS の下準備
まずは、スクロール時にアニメーションさせたい要素に共通のクラス fade-in を付与し、初期状態では透明かつ少し下にずらしたスタイルを設定します。
Html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ふわっとスクロールデモ</title> <link rel="stylesheet" href="styles.css"> </head> <body> <section class="fade-in">セクション1のコンテンツ</section> <section class="fade-in">セクション2のコンテンツ</section> <section class="fade-in">セクション3のコンテンツ</section> <script src="script.js"></script> </body> </html>
Css/* styles.css */ body { font-family: sans-serif; line-height: 1.6; } section { max-width: 800px; margin: 100px auto; padding: 40px; background: #f9f9f9; border-radius: 8px; } /* アニメーション前の状態 */ .fade-in { opacity: 0; transform: translateY(20px); transition: opacity 0.6s ease-out, transform 0.6s ease-out; } /* アニメーション完了時に付与するクラス */ .fade-in.visible { opacity: 1; transform: translateY(0); }
ここで重要なのは、transition プロパティで アニメーションの時間とイージング を指定しておくことです。visible クラスが付与された瞬間に自動的にフェードインとスライドインが開始されます。
ステップ2:Intersection Observer の設定
次に、JavaScript で Intersection Observer を作成し、.fade-in 要素を監視します。
Js// script.js document.addEventListener('DOMContentLoaded', () => { const options = { root: null, // ビューポートを基準に rootMargin: '0px 0px -100px 0px', // 下方向に 100px のマージンを設定(早めにトリガー) threshold: 0 // 要素が1ピクセルでも見えたらコールバック }; const observer = new IntersectionObserver((entries, obs) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('visible'); // 目的が「一度だけ」アニメーションなら監視を停止 obs.unobserve(entry.target); } }); }, options); // 監視対象の要素をすべて取得 const targets = document.querySelectorAll('.fade-in'); targets.forEach(el => observer.observe(el)); });
ポイント解説
rootMarginに負の値を入れると、要素がビューポートの下端に到達する 100px 前にコールバックが走ります。これにより、スクロール途中で「先読み」的にふわっと表示できます。threshold: 0は「要素がほんの少しでも見えたら」発火させる設定です。0.5にすれば半分見えた時点でトリガーしますが、ふわっと感を保つなら 0 が自然です。obs.unobserve(entry.target)で対象要素の監視を解除しています。これにより、同じ要素が再びビューポート外に出たときに余計な再描画が走らず、パフォーマンスが向上します。
付録:遅延や方向を変えるカスタマイズ例
1. 遅延(stagger)を入れる
複数要素が連続して現れる場合、少しずつ遅延させるとリズミカルです。CSS で transition-delay を変数化し、JavaScript でインデックスに応じて設定します。
Css/* 変数を利用した遅延 */ .fade-in { --delay: 0s; transition-delay: var(--delay); }
Jstargets.forEach((el, i) => { el.style.setProperty('--delay', `${i * 0.15}s`); observer.observe(el); });
2. スライド方向を変える
Y方向以外に X方向や回転も組み合わせられます。
Css/* 左からスライドイン */ .fade-in.from-left { transform: translateX(-30px); } .fade-in.from-left.visible { transform: translateX(0); }
HTML 側で class="fade-in from-left" と指定すれば、左方向からのフェードインが実現できます。
ハマった点やエラー解決
| 現象 | 原因 | 解決策 |
|---|---|---|
| アニメーションが一度も起きない | rootMargin が大きすぎて要素がビューポートに入ってもコールバックが発火しない |
rootMargin の負の値を小さく、もしくは 0px に変更 |
| スクロールすると突然要素がちらつく | transition が指定されていない、または opacity と transform が別々のクラスに分かれている |
同一要素に対して transition をまとめて記述し、クラス切り替えは visible のみ |
| 複数ブラウザで挙動が異なる | IntersectionObserver が未サポート(古い IE 等) |
必要に応じて polyfill(intersection-observer npm パッケージ)を導入 |
パフォーマンス最適化のヒント
- Observe する要素は必要最小限に絞る。大量の要素を一括監視すると計算コストが増大します。
requestAnimationFrameと併用しない:Intersection Observer が内部で最適化されているため、スクロールハンドラでrequestAnimationFrameを重ねると逆に負荷が増えます。- CSS の
will-changeは慎重に:will-change: opacity, transform;を付与すると GPU レイヤーが作られますが、過剰に指定するとメモリを圧迫します。対象はアニメーションが確実に走る要素だけに限定しましょう。
まとめ
本記事では、スクロールに連動して要素がふわっと現れるアニメーションを、Intersection Observer と CSS Transition の組み合わせだけで実装する手順を解説しました。
- Intersection Observer でビューポートへの侵入を検知し、クラス切り替えで CSS アニメーションを発火
rootMarginやthresholdで「先読み」や「遅延」を調整し、自然な UX を実現- カスタマイズ例(遅延、方向変更)やハマりポイントと対処法を紹介
この手法を取り入れることで、ページの動きが格段に滑らかになり、訪問者のエンゲージメント向上が期待できます。次は、スクロールトリガーの パララックス効果や スクロール進捗に応じた数値カウントアップといった、さらにリッチなインタラクションへ挑戦してみましょう。
参考資料
- MDN Web Docs – Intersection Observer API
- CSS Tricks – A Complete Guide to CSS Transitions
- 「Web Animation」中村 典子, 2022, O'Reilly Media(スクロール連動アニメの実装パターン集)