スクロールが特定のエリアに入ったかどうかを検知するjQuery

目次
  1. スクロールが特定のエリアに入ったかどうかを検知するjQuery
    1. 補足:jQueryで書く場合
    2. 特定のエリアに入った時にアイテムを表示する例
  2. おわり

スクロール時に特定のエリアに入ったかどうかを検知するためのjQueryの書き方です。

背景色とのコントラスト比で色を追従するアイテムの色を変更したい場合や、特定のエリアのみ表示するようなアイテムを作る際に使われたりします。

型だけ覚えておけば使い回せて便利なので、ぜひお試しください!

今はjQueryを使わなくても、JavaScriptのIntersectionObserverで書けます。この記事では先にIntersectionObserverでの書き方を紹介し、jQueryでの書き方は補足として残しています。

スクロールが特定のエリアに入ったかどうかを検知するjQuery

以下のような、スクロールがセクション3に入った時にヘッダーの色が赤に変わる例を作ってみました。

HTMLとしては、以下のようなものを用意しました。
対象となるエリアに対して.target-areaを指定してあげます。

<div class="section section1">
	<div class="section-content">セクション1</div><!-- /section-content -->
</div><!-- /section -->
<div class="section section2">
	<div class="section-content">セクション2</div><!-- /section-content -->
</div><!-- /section -->
<div class="section section3 target-area">
	<div class="section-content">セクション3</div><!-- /section-content -->
</div><!-- /section -->
<div class="section section4">
	<div class="section-content">セクション4</div><!-- /section-content -->
</div><!-- /section -->
<div class="section section5">
	<div class="section-content">セクション5</div><!-- /section-content -->
</div><!-- /section -->

CSSでは、各セクションに対して適当な色と高さを指定してあげています。

.section {
	height: 600px;
	background: #ccc;
	position: relative;
	transition: all 0.3s ease 0s;
}
.section1 {
	background: #FFFDE7;
}
.section2 {
	background: #E1F5FE;
}
.section3 {
	background: #BBDEFB;
}
.section4 {
	background: #C8E6C9;
}
.section5 {
	background: #FFECB3;
}

そして、JavaScriptのIntersectionObserverで判定を行います。

const target = document.querySelector(".target-area");

const observer = new IntersectionObserver(function(entries) {
	entries.forEach(function(entry) {
		if (entry.isIntersecting) {
			document.body.classList.add("is-in"); // 対象エリアに入った場合
		} else {
			document.body.classList.remove("is-in"); // 対象エリアから出ている場合
		}
	});
}, {
	rootMargin: "0px 0px -100% 0px" // 画面の一番上の線で判定する
});

observer.observe(target);

IntersectionObserverは、要素が画面に入ったときや出たときに、ブラウザが知らせてくれる仕組みです。スクロールのたびに位置を計算する必要がなく、jQueryも要りません。

rootMarginの-100%で、判定に使う範囲を画面の一番上の線まで縮めています。これで、後で紹介するjQueryの例と同じく「画面の上端が対象エリアの中にあるか」で判定できます。対象エリアが少しでも画面に入ったら判定したい場合は、rootMarginの指定を外してください。

補足:jQueryで書く場合

そして、jQueryでスクロールイベントを取得して判定を行っています。

jQuery(window).scroll(function() {
	let scrollTop = jQuery(window).scrollTop(); // スクロール上部の位置
	let areaTop = jQuery(".target-area").offset().top; // 対象エリアの上部の位置
	let areaBottom = areaTop + jQuery(".target-area").innerHeight(); // 対象エリアの下部の位置

	if (scrollTop > areaTop && scrollTop < areaBottom) {
		jQuery("body").addClass("is-in"); // スクロールが対象エリアに入った場合
	} else {
		jQuery("body").removeClass("is-in"); // スクロールが対象エリアから出ている場合
	}
});

取得する値としては以下の3つです。

  • スクロール上部の位置を取得
  • 対象エリアの上部の位置
  • 対象エリアの下部の位置

そして、スクロール上部が対象エリアの上部の位置を超えた時と、スクロール上部が対象エリアの下部の位置を超えた時の2つの判定を行うような感じです。

今回の場合だと、スクロールが対象エリアに入った場合は、bodyに対して.is-inというクラスを付与して、対象エリア外の時はbodyから.is-inクラスを削除しています。

bodyにつけることでサイト全体への効果を与えることが可能です。汎用的に使いたいクラスなどはbodyにつけると管理しやすくなっておすすめです。

ローディング判定やスクロール判定をbodyで一元管理すると捗る

特定のエリアに入った時にアイテムを表示する例

もう一つよくある例として、特定のエリアに入った時にアイテムを表示する例を見ていきます。

特定のエリアに入った時にアイテムを表示する例です。セクション3に入ったら右側から「特定のエリアで出てくる」が伸びてくるように作っています。

方法としては最初に紹介したものとベースは同じです。特定のエリアに入った時を監視して、bodyにクラスを付与。そして今回でいうと「特定のエリアで出てくる」というラベルに対して、処理を加えてあげるようなイメージです。

表示する用のHTMLとCSSを以下のように作成して、.is-inクラスが付与されたら、translateX(0)として隠してあったアイテムを表示するようにしています。

<div class="floating"><a href="#">特定のエリアで出てくる</a></div>
.floating {
	position: fixed;
	transform: translateX(100%);
	transition: all 0.3s ease 0s;
	top: 120px;
	right: 0;
}

.is-in .floating {
	transform: translateX(0);
}

※ JavaScriptは先ほどのIntersectionObserverのコードがそのまま使えます。

※ jQueryについては先ほどと同様なので割愛します。

おわり

スクロールが特定のエリアに入ったかどうかを検知するjQueryと、実際の例を2つ紹介しました。

今はIntersectionObserverで書くのがおすすめです。jQueryで書く場合のポイントは、以下の3つです。

  • スクロール上部の位置を取得
  • 対象エリアの上部の位置
  • 対象エリアの下部の位置

スクロール上部が対象エリアの上部の位置を超えた時と、スクロール上部が対象エリアの下部の位置を超えた時の2つの判定を行うだけの簡単な処理なので、型だけ覚えておいて使い回せるようにしておくと便利です。

WordPressでお悩みの方はお気軽にご相談ください。

ちょっとしたお困り事からサイト全体のリニューアルのようなご依頼まで、お悩みに応じて柔軟に対応いたします。

この記事を書いた人

はにわまん

HPcode代表。300件以上のWordPress案件を対応してきました。ちょっとしたWordPressのカスタマイズからブロックテーマでのリニューアルまで。更新できるWordPressサイトが好きです。