JavaScript03: スクロールイベントでWebを動かそう

  • URLをコピーしました!

Webサイトに動きをつけるための技術の一つとして、スクロールイベントがあります。JavaScriptを使って、スクロールに応じた表示・非表示。getBoundingClientRect()関数を使っての画像の表示。IntersectionObserverを使ったスクロールの監視などを行います!

目次

スクロールイベントで表示・非表示を切り替える

JavaScriptを使ったスクロールイベントの基本的な使い方を行います。ここでは下にスクロールしたら表示され、上にスクロールしたら非表示になる動きを作成します。このような動きは、通知バーやスクロールトップボタンなどに活用されます。

See the Pen スクロールイベントで表示・非表示を切り替える by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

HTML解説

<div class="scroll-toggle hidden">
  <p>スクロール中に右の下に<br>下記のimgが表示します。</p>
  <img src="https://placehold.jp/09a53f/ffffff/200x200.png">
</div>
<div style="height: 2000px;">
    <p>このページをスクロールして動作を確認してください。</p>
</div>

CSS解説

.scroll-toggle {
    position: fixed;
    bottom: 10px;
    right: 10px;
    background-color: #333;
    color: #fff;
    padding: 10px 20px;
    border-radius: 5px;
    opacity: 0;
    transform: translateY(50px);
    transition: opacity 0.5s ease, transform 0.5s ease;
}
.scroll-toggle.visible {
    opacity: 1;
    transform: translateY(0);
}
  1. .scroll-toggle:
    • position: fixed;:
      • 要素を画面の固定位置に配置します(画面をスクロールしても動きません)。
      • bottom: 10px;right: 10px; によって、画面右下に配置。
    • background-color: #333;color: #fff;:
      • 背景色を暗いグレー、テキスト色を白に設定。
    • opacity: 0;:初期状態で要素を非表示にします。
    • transform: translateY(50px);:垂直方向に50px下に移動させ、スクロール時にアニメーションで元の位置に戻します。
    • transition:opacitytransform の変化を0.5秒かけてスムーズに実行。
  2. .scroll-toggle.visible:
    • opacity: 1;:要素を完全に表示します。
    • transform: translateY(0);:要素を元の位置に戻します(アニメーションが適用されます)。

JavaScript解説

let lastScrollY = window.scrollY; // 最初のスクロール位置を取得
const toggleElement = document.querySelector('.scroll-toggle');

const onScroll = () => {
    const currentScrollY = window.scrollY;

    if (currentScrollY > lastScrollY) {
        // 下にスクロール中
        toggleElement.classList.add('visible');
    } else {
        // 上にスクロール中
        toggleElement.classList.remove('visible');
    }

    lastScrollY = currentScrollY; // スクロール位置を更新
};

window.addEventListener('scroll', onScroll);
  1. let lastScrollY = window.scrollY;:
    • 最初のスクロール位置を取得し、変数 lastScrollY に保存します。この値を後で現在のスクロール位置と比較します。
  2. const toggleElement = document.querySelector('.scroll-toggle');:表示・非表示を切り替える対象要素(.scroll-toggle)を取得します。
  3. onScroll 関数:
    • const currentScrollY = window.scrollY;:現在のスクロール位置を取得します。
    • if (currentScrollY > lastScrollY):
      • 現在のスクロール位置が前回の位置よりも大きければ「下にスクロール中」と判定。
      • この場合、toggleElement にクラス visible を追加し、要素を表示します。
    • else:
      • 現在のスクロール位置が小さければ「上にスクロール中」と判定。
      • この場合、クラス visible を削除し、要素を非表示にします。
    • lastScrollY = currentScrollY;:現在のスクロール位置を lastScrollY に保存し、次回の比較に使用します。
  4. window.addEventListener('scroll', onScroll);:
    • スクロールイベントが発生するたびに、onScroll 関数を実行します。
    • ブラウザがスクロールを検知すると、自動的に処理を繰り返します。

スクロールでイメージを表示

スクロールするとイメージが順番に表示される動きを作ります。getBoundingClientRect()関数を使用してビューポート内で見えているかを判定

See the Pen スクロール01 by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

HTML解説

<h1>スクロールを下げてください</h1>
<p>スクロールを下げると左から順番に画像が表示します</p>
<div class="image-container">
    <img src="https://placehold.jp/f9b806/ffffff/300x200.png" alt="Example Image 1" class="hidden">
    <img src="https://placehold.jp/f90606/ffffff/300x200.png" alt="Example Image 2" class="hidden">
    <img src="https://placehold.jp/09a53f/ffffff/300x200.png" alt="Example Image 3" class="hidden">
</div>

CSS解説

.hidden {
    opacity: 0;
    transform: translateY(100px);
    transition: opacity 1s ease-out, transform 1s ease-out;
}
.visible {
    opacity: 1;
    transform: translateY(0);
}

.hidden

  • opacity: 0;
    • 要素を透明にしておくので、最初は見えません。
  • transform: translateY(100px);
    • 要素を垂直方向に100px下へ移動します。スクロールが開始すると下へ下がるので徐々に表示します。
  • transition: opacity 1s ease-out, transform 1s ease-out;
    • アニメーションをスムーズかつゆっくり表示させます。

.visible

  • opacity: 1;
    • 要素を完全に表示します。
  • transform: translateY(0);
    • 要素を元の位置に戻します。

JavaScriptの解説

const images = document.querySelectorAll('.hidden');

const onScroll = () => {
    images.forEach((image, index) => {
        const rect = image.getBoundingClientRect();
        if (rect.top < window.innerHeight && rect.bottom > 0) {
            setTimeout(() => {
                image.classList.add('visible');
            }, index * 300); // 順番に表示させるために遅延を追加
        }
    });
};

window.addEventListener('scroll', onScroll);
  1. document.querySelectorAll('.hidden'):
    • .hidden クラスが付けられているすべての要素を取得します。
  2. window.addEventListener('scroll', onScroll):
    • スクロールイベントが発生するたびに、onScroll関数が実行されます。

const onScrol関数内

  • images.forEach((image, index) => { ... }):
    • 各イメージ要素に対してループを実行します。
    • indexを使用して、それぞれのイメージに遅延時間を追加します。
  • setTimeout(() => { image.classList.add('visible'); }, index * 300);:
    • 最初のイメージはすぐに表示され、次のイメージは300ms後、その次は600ms後に表示されるようになります。

上記の方法では、スクロールイベントごとに計算が行われるため、画像が多い場合にはパフォーマンスに影響を与える場合があります。

Intersection Observer

Intersection Observerは、Webページの中で特定の要素が画面に見える位置に来たかどうかを自動でチェックしてくれる仕組みです。これを使うと、スクロールイベントを使った手動の計算が必要なくなり、より効率的に動作します。また、ページにたくさんの要素があっても、動きが重くならずにスムーズに処理できます。

HTML/CSSは同じコードを使います。

See the Pen Intersection Observer by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

JavaScriptの解説

const images = document.querySelectorAll('.hidden');

const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach((entry) => {
        if (entry.isIntersecting) {
            // 遅延を画像ごとに適用する
            const delay = parseInt(entry.target.dataset.delay) || 0;
            setTimeout(() => {
                entry.target.classList.add('visible');
            }, delay);
            observer.unobserve(entry.target); // 一度表示されたら監視を解除
        }
    });
}, {
    threshold: 0.1, // 10%表示されたらトリガー
    rootMargin: '0px', // 監視範囲のマージン
});

// 各画像にデータ属性で遅延を設定
images.forEach((image, index) => {
    image.dataset.delay = index * 300; // 各画像に300msずつ遅延を追加
    observer.observe(image);
});

Intersection Observerの使い方

  1. Observerの作成
    • new IntersectionObserver(callback, options) を使って作成します。
      • callback: 要素が見える位置に来たとき、または見えなくなったときに実行される関数。
      • options: チェックの仕方を調整するための設定。
    const observer = new IntersectionObserver(callback, options);
  2. 監視対象を登録
    • 作成した observer を使って、特定の要素を監視するよう登録します。
    observer.observe(targetElement);
  3. 監視を解除
    • 必要がなくなったら、特定の要素やすべての要素の監視を解除します。
    observer.unobserve(targetElement); // 特定の要素を解除
    observer.disconnect(); // すべての要素を解除

コールバック関数の中身

監視中の要素が見える位置に来ると、callback 関数が実行されます。callback には次のような情報が渡されます。

  • entries: 監視中の要素ごとの状態(リスト形式)。
    • 例: 画面に表示されているかどうか、どのくらい表示されているか。

entry の主な内容

  • entry.target: 現在の監視対象(例えば <img> タグ)。
  • entry.isIntersecting: 要素が画面内に見えているかどうか。
    • true: 要素が見えている。
    • false: 要素が見えていない。
const callback = (entries) => {
    entries.forEach((entry) => {
        if (entry.isIntersecting) {
            entry.target.classList.add('visible'); // 表示を開始
        }
    });
};

オプションの設定

IntersectionObserver の動きをカスタマイズするには、options を設定します。

  • threshold:
    • 要素がどのくらい画面に見えたらコールバックを実行するか。
    • 例: 0.1 は要素の10%が見えたら実行。
  • rootMargin:
    • 画面の範囲を拡大・縮小する設定。
    • 例: '0px 0px -50px 0px' は画面下方向を50px拡張して監視。

スクロールしたら左から右に出現する

IntersectionObserverを使って、今度は左から順番に表示させるように変更します。その場合は、CSSのtransformプロパティでY方向ではなくX方向に移動させ、JavaScriptで画像ごとに適切な遅延を設定するよう変更していきます。HTMLはそのまま使います。CSSとJavaScriptは若干の変更があります。

See the Pen Intersection Observer left_in by Yoshiko Nakamura (@Yoshiko-Nakamura) on CodePen.

CSS解説

.hidden {
    opacity: 0;
    transform: translateX(-200px); /* X方向(左)に移動 */
    transition: opacity 1s ease-out, transform 1s ease-out;
}
.visible {
    opacity: 1;
    transform: translateX(0); /* 元の位置に戻す */
}

.hidden

  • transform: translateX(-200px);
    • 要素を水平方向に-200px左へ移動します。スクロールが開始すると左へ右に徐々に表示します。

JavaScript解説

const images = document.querySelectorAll('.hidden');

const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach((entry, index) => {
        if (entry.isIntersecting) {
            setTimeout(() => {
                entry.target.classList.add('visible');
            }, index * 300); // 各画像に300msずつ遅延を追加
            observer.unobserve(entry.target); // 一度表示されたら監視を解除
        }
    });
}, {
    threshold: 0.1, // 10%表示されたらトリガー
    rootMargin: '0px', // 監視範囲のマージン
});

// 各画像を監視対象に追加
images.forEach((image) => {
    observer.observe(image);
});

setTimeout を使って画像ごとに異なる遅延を設定しています。index * 300 で、画像の順番に応じて300msずつ遅延。

よかったらシェアしてね!
  • URLをコピーしました!
目次