スクロールアニメーションとは

スクロールして要素が画面内に入ったタイミングで、フェードインなどのアニメーションを再生する技法。

概要

ページをスクロールして要素が画面内に入ったタイミングで、その要素をふわっと浮かび上がらせるようにアニメーションさせる技法です。 最初は透明で少し下にずらしておき、画面に入った瞬間にクラスを付け替えて本来の位置・不透明度に戻す実装が一般的で、 要素が画面に入ったかどうかの判定には IntersectionObserver という JavaScript の仕組みがよく使われます。

別名

表記ゆれ:スクロールアニメーション、スクロールフェードイン、スクロール連動、IntersectionObserver

「スクロールで要素をふわっと出して」という言い方でも伝わります。IntersectionObserver は実装に使う API の名前です。

AI への伝え方

「スクロールしたら要素がふわっと表示されるようにして」で伝わります。 一度表示されたら二度とアニメーションさせないのか、画面から外れるたびに繰り返すのかを伝えると仕様がぶれません。 動きに敏感なユーザーのために、prefers-reduced-motion: reduce の環境ではアニメーションさせず最初から表示しておく配慮も必要です。

似たパーツとの違い

「パララックス」は背景と本文がスクロール量に応じて異なる速さで動く技法で、スクロール中ずっと動き続けます。スクロールアニメーションは要素が画面に入った一瞬だけ再生する点が違います。

デモ

コード

HTML
<div class="scroll-animation-demo">
  <p class="scroll-animation-demo__intro">下にスクロールすると、要素が順番にふわっと現れます。</p>
  <div class="scroll-animation-demo__spacer"></div>
  <div class="scroll-animation-demo__item">カード 1</div>
  <div class="scroll-animation-demo__item">カード 2</div>
  <div class="scroll-animation-demo__item">カード 3</div>
  <div class="scroll-animation-demo__spacer"></div>
</div>
CSS
.scroll-animation-demo {
  font-family: sans-serif;
  color: #333333;
}

.scroll-animation-demo__intro {
  margin: 0 0 16px;
}

.scroll-animation-demo__spacer {
  height: 260px;
}

.scroll-animation-demo__item {
  padding: 24px;
  margin-bottom: 16px;
  border-radius: 8px;
  background: #0017c1;
  color: #ffffff;
  text-align: center;
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.scroll-animation-demo__item.is-visible {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .scroll-animation-demo__item {
    transition: none;
    opacity: 1;
    transform: none;
  }
}
JS
const items = document.querySelectorAll(".scroll-animation-demo__item");

const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.target.classList.add("is-visible");
      }
    });
  },
  { threshold: 0.3 }
);

items.forEach((item) => observer.observe(item));