スクロールに合わせて要素がふわっと現れる演出は、記事一覧、特徴紹介、料金表、FAQ など、いろいろなUIで使われます。
ただし、勢いで実装すると「毎フレーム scroll を監視して重くなる」「一度表示した要素が何度も切り替わって落ち着かない」といった問題が出やすいです。
この記事では、Scroll Trigger Animation の基本的な考え方を、初心者向けにできるだけシンプルに整理します。
今回は Intersection Observer を使って、要素が画面内に入ったタイミングでクラスを付け、自然に表示する方法を作ります。
この記事を読むと、次のことがわかります。
- Scroll Trigger Animation の基本構造
- scrollイベント連打ではなく、Intersection Observer を使う理由
- fade / slide を組み合わせた見やすい表示演出の作り方
- 複数要素を順番に見せるときの考え方
スクロール系アニメーションにはいくつか種類があります。 基本の「表示系アニメーション」については、 Scroll Reveal Animation でも解説しているので、 あわせて読むと理解しやすくなります。
1.Scroll Trigger Animation とは?
Scroll Trigger Animation は、スクロール位置をきっかけに要素の見た目を変える演出です。
たとえば次のような場面でよく使われます。
- セクション見出しが下からふわっと出る
- カード一覧がスクロールに合わせて順番に表示される
- 画像とテキストが画面に入ったタイミングで現れる
- CTAボタンや機能紹介を目立たせる
ページ読み込み直後に全部動くのではなく、ユーザーがそこまで読んだ瞬間に表示されるのがポイントです。
このおかげで、ページ全体が見やすくなり、内容の区切りも伝わりやすくなります。
2.よくある実装の問題
Scroll Trigger Animation は見た目は簡単そうですが、作り方によっては扱いづらくなります。
よくあるのは、scroll イベントで毎回位置を計算する方法です。
window.addEventListener('scroll', () => {
const rect = element.getBoundingClientRect();
if (rect.top < window.innerHeight) {
element.classList.add('is-visible');
}
});この方法でも動きますが、要素数が増えると毎回判定が走りやすく、管理もしづらくなります。
また、表示済みかどうかの制御を足し始めると、コードが少しずつ複雑になります。
そこで今回は、表示判定をブラウザ側に任せやすい Intersection Observer を使います。
なお、スクロールイベントを毎フレーム処理するとパフォーマンスに影響が出やすいため、 フレームレートとパフォーマンス の考え方もあわせて押さえておくと理解が深まります。
3.今回の完成イメージ
今回作るのは、以下の流れです。
- 最初は要素を少し下にずらして透明にしておく
- 要素が画面内に入ったら
is-visibleクラスを付ける opacityとtransformの transition で自然に表示する
アニメーション自体はシンプルですが、実案件でもかなり使いやすい形です。
まずはHTML
まずは表示対象のカードを並べます。
それぞれに js-scroll-item を付けて、JavaScript からまとめて監視できるようにします。
<section class="features">
<h2 class="section-title js-scroll-item">Scroll Trigger Animation</h2>
<div class="card-list">
<article class="card js-scroll-item">
<h3>Fast Setup</h3>
<p>Intersection Observer を使って、画面に入った要素を自然に表示します。</p>
</article>
<article class="card js-scroll-item">
<h3>Clean Motion</h3>
<p>opacity と transform だけで、見やすく軽いアニメーションにします。</p>
</article>
<article class="card js-scroll-item">
<h3>Reusable Pattern</h3>
<p>クラスの付け替えだけなので、いろいろなセクションに再利用できます。</p>
</article>
</div>
</section>次にCSS
初期状態では少し下にずらし、透明にしておきます。
表示タイミングで is-visible が付いたら、元の位置と不透明状態に戻します。
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
font-family: sans-serif;
background: #0f1115;
color: #f5f7fb;
}
.features {
width: min(960px, calc(100% - 32px));
margin: 0 auto;
padding: 120px 0;
}
.section-title {
margin: 0 0 32px;
font-size: clamp(28px, 4vw, 48px);
line-height: 1.2;
}
.card-list {
display: grid;
gap: 20px;
}
.card {
padding: 24px;
border-radius: 20px;
background: #171b22;
border: 1px solid rgba(255, 255, 255, 0.08);
}
.card h3 {
margin: 0 0 12px;
font-size: 20px;
}
.card p {
margin: 0;
color: rgba(255, 255, 255, 0.72);
line-height: 1.7;
}
/* Scroll Trigger 初期状態 */
.js-scroll-item {
opacity: 0;
transform: translateY(24px);
transition:
opacity 0.7s ease,
transform 0.7s ease;
will-change: opacity, transform;
}
/* 表示後 */
.js-scroll-item.is-visible {
opacity: 1;
transform: translateY(0);
}JavaScriptで表示タイミングを判定する
ここでは IntersectionObserver を使って、要素が画面内に入ったタイミングで is-visible を付けます。
const items = document.querySelectorAll('.js-scroll-item');
const observer = new IntersectionObserver((entries, obs) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) return;
entry.target.classList.add('is-visible');
obs.unobserve(entry.target);
});
}, {
threshold: 0.2
});
items.forEach((item) => {
observer.observe(item);
});この実装のポイント
①threshold: 0.2 で少し見えたら発火する
threshold は、対象要素がどのくらい見えたら判定するかの基準です。
threshold: 0.2この場合は、要素の20%くらいが見えたら発火します。
早めに出したいなら小さめ、しっかり見えてから出したいなら大きめにします。
②表示後に unobserve() している
一度表示したら、今回は再監視しなくてよいので外しています。
obs.unobserve(entry.target);これを入れておくと、
「一回表示されたらそのまま」
という自然な見た目になりやすく、処理も整理しやすいです。
③動かしているのは opacity と transform
今回のアニメーションは次の2つだけです。
opacitytransform: translateY()
この2つは比較的扱いやすく、UIアニメーションの基本でもあります。
Scroll Trigger は凝りすぎるより、まずは軽くて読みやすい動きにするのが大事です。
今回のようなアニメーションの質は、イージングの設定でも大きく変わります。 詳しくは easing / cubic-bezier を参考にしてみてください。
4.少し発展:順番に出すと気持ちいい
カードが複数ある場合は、少しずつ遅延を付けると、より見やすくなります。
たとえばHTML側で style="transition-delay: 0.1s" のように指定してもよいです。
<article class="card js-scroll-item" style="transition-delay: 0.1s;">
...
</article>
<article class="card js-scroll-item" style="transition-delay: 0.2s;">
...
</article>
<article class="card js-scroll-item" style="transition-delay: 0.3s;">
...
</article>このやり方なら、JavaScriptを増やさなくても、見た目だけ順番表示にできます。
ただし、遅延を大きくしすぎるとテンポが悪くなるので、
0.05秒〜0.15秒くらいの差から始めると扱いやすいです。
5.実務で意識したいこと
Scroll Trigger Animation は便利ですが、入れすぎると逆に読みにくくなります。
特に本文中の小さな要素すべてを動かすと、ページ全体が落ち着かなく見えることがあります。
意識したいのは次の3つです。
①重要なまとまりだけ動かす
見出し、カード群、画像+説明ブロックなど、
セクション単位で動かすと自然です。
②動きは控えめにする
Scroll Trigger は「驚かせる」より、
読み進めやすくする補助として使う方が相性がよいです。
③一度表示したらそのままにする
毎回スクロールで出たり消えたりすると、情報が安定しません。
記事ページや紹介ページでは、一度見せたらそのままが基本的に使いやすいです。
スクロールに関するアニメーションは他にもいくつかパターンがあります。 ページ全体の動きを制御するなら Scroll Snap Animation や、 奥行きを演出する Parallax Scroll Animation もおすすめです。
6.実験:Scroll Trigger Animation を観察してみよう
下のデモでは、要素が画面内に入ったときに is-visible が付与され、ふわっと表示されます。
表示位置やタイミングを少し変えるだけでも、見え方の印象が変わるので観察してみてください。
観察ポイント
- どの位置で表示が始まると自然に見えるか
translateYの距離が大きすぎないか- fade と slide の組み合わせが読みやすさを邪魔していないか
- カードを順番表示にしたとき、テンポが重くなっていないか
7.まとめ
Scroll Trigger Animation は、スクロールに応じて必要な情報を自然に見せるための基本パターンです。
今回のポイントは以下です。
- 表示判定は
IntersectionObserverを使う - 要素が見えたら
is-visibleを付ける - アニメーションは
opacityとtransformを中心にする - 一度表示したら
unobserve()で外すと扱いやすい
まずは今回のような fade + slight slide の形を土台にすると、いろいろなUIへ展開しやすいです。
派手さよりも、読みやすさと使いやすさを崩さないことを意識すると、長く使える Scroll Trigger Animation になります。
Scroll Animationシリーズ

コメントを残す