【JavaScript 】要素が画面内にあるかどうかを判別する方法

Webページ上の特定の要素が、ユーザーのスクロールによって画面内(ビューポート内)に表示されているかどうかを判別する方法は、インタラクティブな機能を実装する際に非常に役立ちます。例えば、画像を遅延読み込みしたり、スクロール時にアニメーションを発火させたりする場合です。ここでは、要素がビューポート内にあるかどうかを確認するための2つの方法を紹介します。

IntersectionObserver APIを使用する方法

IntersectionObserverは、指定した要素がビューポート内に入ったり出たりするのを監視するための強力なAPIです。リソース効率が高く、シンプルに実装できるため、スクロールイベントを手動で処理するよりも優れた選択肢です。

以下は、IntersectionObserverを使って要素が画面内にあるかどうかを確認する基本的なコード例です。

// 対象要素の監視を開始する関数
function observeElement(element) {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        console.log('要素がビューポート内にあります');
      } else {
        console.log('要素がビューポート外です');
      }
    });
  });

  observer.observe(element); // 対象の要素を監視
}

// 監視したい要素を取得
const targetElement = document.querySelector('.target');
observeElement(targetElement);

IntersectionObserverは、監視対象の要素(例: .target)がビューポートに表示された場合にisIntersectingプロパティがtrueになり、ビューポート外に出た場合はfalseになります。これにより、要素の可視状態を簡単に判断できます。

要素の位置とウィンドウのスクロール位置を比較する方法

もう一つの方法は、要素の位置を取得して、ウィンドウのビューポートと比較するものです。getBoundingClientRect()メソッドを使って、要素の寸法とそのスクリーン上の位置を取得し、それをスクロール位置と比較します。

function isElementInViewport(element) {
  const rect = element.getBoundingClientRect();
  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
    rect.right <= (window.innerWidth || document.documentElement.clientWidth)
  );
}

// 監視したい要素を取得
const targetElement = document.querySelector('.target');

// スクロールイベント時に要素がビューポート内かどうか判別
window.addEventListener('scroll', () => {
  if (isElementInViewport(targetElement)) {
    console.log('要素がビューポート内にあります');
  } else {
    console.log('要素がビューポート外です');
  }
});

この方法では、getBoundingClientRect()で取得した要素の座標(top、bottom、left、right)をビューポートの大きさと比較し、要素が画面内にあるかどうかを判定します。スクロールイベントごとに実行されるため、リアルタイムに要素の状態をチェックできます。

まとめ

IntersectionObserverは、パフォーマンスの観点から推奨される方法であり、スクロールイベントのリスナーを手動で作成する必要がなく、より効率的に要素の可視状態を確認できます。一方で、getBoundingClientRect()を使った方法は、ブラウザサポートの広さやシンプルな用途には向いています。状況に応じて適切な方法を選んで実装してみてください。