スクロールで「ふわっ」と登場するアニメーションを作成する方法 縦長画像バージョン

最近、Webサイトの中で「画像がスクロールに応じてふわっと出てくる演出」を取り入れる機会がありました。
読み進めるにつれて、静かに、でも印象的に現れる。
そんな「ちょうどいい存在感」を演出するのに、Intersection Observer を使って実装してみました。

▼ CSS(初期状態とアニメーション)

.fade-in {
opacity: 0;
transform: translateY(40px);
transition: all 0.8s ease-out;
}

.fade-in.show {
opacity: 1;
transform: translateY(0);
}

▼ JavaScript(スクロールで発火)

const fadeIns = document.querySelectorAll('.fade-in');

const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('show');
observer.unobserve(entry.target);
}
});
}, {
threshold: 0, // 要素が少しでも見えたら発火
rootMargin: "0px 0px -40% 0px" // ← ビューポート下から40%の範囲に入ったら発火
});

fadeIns.forEach(el => observer.observe(el));

これで完成!と思って、PCで確認してみると……

あれ、もう出てる? 思ったより早く出てきてしまい、せわしない…

そうなんです。
縦長の画像を使っていたため、スクロールで画像の上の方がチラッと入っただけで、すでにIntersection Observerが「入ったね!」と反応してしまったのです。

たとえば画像の高さが800px、でも画面は600pxだったりすると、ちょっと入っただけで「20〜30%見えている」状態と判定されてしまい、せわしない動きになる事態に。

解決策:threshold をちゃんと使う

ここで重要なのが threshold の設定です。

threshold: 0.7

これは「要素全体のうち、70%が画面に入ったら発火していいよ」という意味です。
縦長の要素でも「だいぶ入ってきたな」というタイミングになるので、もったいつけた表示に最適です。

ついでに rootMargin を少し調整すると、より細かいコントロールも可能になります。

▼ 改良版 JavaScript(しっかり“期待を持たせる”バージョン)

const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('show');
observer.unobserve(entry.target);
}
});
}, {
threshold: 0.7, // 要素の70%が見えたら発火
rootMargin: "0px 0px -10% 0px" // 下から10%のマージンを除外
});

調整して気づいたこと

正直なところ、最初は「rootMarginだけでいけるだろう」と思っていました。
ですが、縦長画像のように要素自体が大きいケースでは、thresholdを併用しないと制御できないというのは完全に盲点でした。

「ふわっと出す」だけでも、要素のサイズや画面の大きさ、スクロール位置など、けっこういろんな条件が絡んできます
特に今回は、見せたいタイミングをコントロールすることの難しさと面白さを学べた良い機会でした。

まとめ

  • スクロールでふわっと登場させるには、Intersection Observer × CSSトランジションが便利
  • 画像が縦長だと早めに発火してしまう落とし穴がある
  • threshold を調整して**「どれだけ見えたら発火するか」を細かく制御**することが大事
  • 「思ったより出てくるの早いな…」と感じたら、それは失敗じゃなくてチューニングのチャンス
Home
サービス
制作実績
デザイナー紹介
公式LINE
問合せ