ジャンルから探す

Web Design English

画像にスクロール連動アニメーションを付ける方法【CSS/curtains.js】

画像にスクロール連動のアニメーションを付ける方法を解説します。

結論から書くと、まずCSSだけで書けないかを検討してください。animation-timeline: view() を使えば、ライブラリを読み込まずにスクロール連動のアニメーションが作れます。WebGLを使った本格的な歪みや波打ちの表現が必要になった段階で、初めてライブラリを足します。

スポンサーリンク

CSSだけでスクロール連動アニメーションを作る

結論:animation-timeline: view() を指定すると、その要素が画面を横切る間だけアニメーションが進みます。JavaScriptは不要です。

通常の animation は時間で進みますが、animation-timeline を指定すると、スクロール位置で進むようになります。スクロールを戻せばアニメーションも巻き戻ります。

@keyframes reveal {
  from {
    opacity: 0;
    transform: translateY(40px) scale(0.95);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.fade-img {
  animation: reveal linear both;
  /* その要素が画面に入る間で進める */
  animation-timeline: view();
  /* 進行の範囲を指定する */
  animation-range: entry 0% cover 40%;
}

animation-range で「いつ始まっていつ終わるか」を決めます。entry 0% は要素が画面の下から入り始めた時点、cover 40% は画面を4割横切った時点です。

カーテンが開くような表現も、クリップパスを動かせばCSSだけで作れます。

@keyframes curtain-open {
  from { clip-path: inset(0 50% 0 50%); }
  to   { clip-path: inset(0 0 0 0); }
}

.curtain-img {
  animation: curtain-open linear both;
  animation-timeline: view();
  animation-range: entry 10% cover 50%;
}

inset(0 50% 0 50%) は左右から50%ずつ隠した状態です。これを0にしていくと、中央から左右に開くカーテンのように見えます。

対応していないブラウザへの備え

結論:Chrome・Edge 115以降と Safari 18以降が対応しています。Firefox は2026年9月時点でまだ既定で無効なので、@supports で分岐させてください。

/* 未対応ブラウザでは最初から表示された状態にする */
.fade-img {
  opacity: 1;
}

@supports (animation-timeline: view()) {
  .fade-img {
    animation: reveal linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 40%;
  }
}

未対応の環境で「画像が見えないまま」にならないよう、初期状態は表示にしておいてください。アニメーションが効かない環境で opacity: 0 のままだと、画像がまったく出てこなくなります。

動きを減らす設定にしている人への配慮も入れます。

@media (prefers-reduced-motion: reduce) {
  .fade-img {
    animation: none;
    opacity: 1;
  }
}

JavaScriptで制御する場合

結論:「一度表示したら戻さない」といった制御が要る場合は、Intersection Observer を使います。

animation-timeline はスクロールに完全連動するため、上にスクロールし直すとアニメーションも戻ります。一度きりの演出にしたいなら、クラスを付けるだけにします。

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add('is-visible');
      // 一度きりにするので監視を外す
      observer.unobserve(entry.target);
    }
  });
}, { threshold: 0.2 });

document.querySelectorAll('.fade-img').forEach((el) => observer.observe(el));
.fade-img {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.6s, transform 0.6s;
}

.fade-img.is-visible {
  opacity: 1;
  transform: none;
}

unobserve() を呼んで監視を外すのがポイントです。これを忘れると、画面外に出るたびに判定が走り続けます。

スポンサーリンク

WebGLで画像を歪ませたい場合

結論:画像を波打たせる、マウスに反応して歪ませるといった表現が必要なら、curtains.js を使います。HTMLの画像要素をWebGLのテクスチャとして扱えるライブラリです。

curtains.js は Martin Laxenaire さんが開発しているバニラJavaScriptのライブラリで、2025年時点でも更新が続いています。<img> や <video> をそのままWebGLの平面(プレーン)に変換し、シェーダーで加工できます。

npmから導入できます。

npm install curtainsjs

基本の考え方は次のとおりです。

  1. キャンバスを置く要素を用意する
  2. その中にアニメーションさせたい <img> を配置する
  3. Curtains を初期化し、画像を含む要素を Plane として登録する
  4. 頂点シェーダーとフラグメントシェーダーで見た目を加工する

シェーダーを書く必要があるため、CSSと比べると学習コストははっきり上がります。「ふわっと出す」「カーテンのように開く」程度の表現なら、前半のCSSで十分です。

導入手順とサンプルはcurtains.js の公式サイトにまとまっています。デモも豊富なので、どこまでできるかを先に見てから判断するのがおすすめです。

どの方法を選ぶか

結論:表現したいことの複雑さで決めてください。ライブラリを読み込むほど、ページは重くなります。

▼方法の使い分け

やりたいこと 方法 追加の読み込み
ふわっと表示する animation-timeline: view() なし
カーテンのように開く clip-path + 同上 なし
一度きりの演出にする Intersection Observer なし(自前のJS)
画像を歪ませる・波打たせる curtains.js ライブラリ

上から順に試して、足りなくなったら次へ進むのが結果的にいちばん軽く済みます。最初からライブラリを入れると、実際には使わない機能まで読み込むことになります。

スクロールに応じて色を変える実装はスクロールに応じて色を変える方法5つにまとめました。この記事と同じ animation-timeline を使います。

マウス操作に反応させる演出なら、マウスストーカーの作り方も参考になります。

この記事の訂正について

この記事は当初「curtain.js」というライブラリを紹介していましたが、内容に誤りがありました。2026年9月に全面的に見直しています。

  • 紹介していた「curtain.js」(作者 Victa)は画像用ではなく、全画面のパネルをめくるjQueryプラグインでした
  • そのcurtain.jsはGitHubで「PROJECT IS NOT MAINTAINED」と明記され、開発が終了しています
  • 記載していた new Curtain() という書き方やオプションは、実際には存在しないものでした
  • 掲載していた公式サイトのURLも現在つながりません

名前のよく似た「curtains.js」(末尾にs)は別のライブラリで、こちらは現役です。画像にアニメーションを付けるという目的に合うのはこちらでした。