ここ最近、ウェブページ内ナビゲーションの現在地の表示(カレント表示)を実装する時は IntersectionObserver を使っています。
以前はスクロールイベントで位置を取って計算していましたが、 IntersectionObserver を使った方が簡単に実装できる上、パフォーマンスの観点でも良いとのことなので、使い方をメモしておきます。
サンプルのデモはこちら
サンプルの解説
<div class="nav">
<ul>
<li><a class="navBtn" href="#section1">section1</a></li>
<li><a class="navBtn" href="#section2">section2</a></li>
<li><a class="navBtn" href="#section3">section3</a></li>
</ul>
</div>
<div id="section1" class="section">section1</div>
<div id="section2" class="section">section2</div>
<div id="section3" class="section">section3</div>
const ACTIVE_CLASS_NAME = 'active';
const buttons = document.querySelectorAll('.navBtn');
buttons.forEach(button => {
const target = document.querySelector(button.getAttribute('href'));
const observer = new IntersectionObserver(([{isIntersecting}]) => {
if (isIntersecting) {
buttons.forEach(el => el.classList.remove(ACTIVE_CLASS_NAME));
button.classList.add(ACTIVE_CLASS_NAME);
}
});
observer.observe(target);
})
- それぞれのナビのボタンの
href
属性から、ターゲットの要素(この例だと #section1, #section2, #section3)を取得します。 -
new IntersectionObserver
でコンストラクターを呼び出し、オブザーバーを作成します。 - オブザーバーのコールバックとして、ボタンの現在地の表示を切り替える処理を渡します。このコールバックは、画面内にターゲットが見えるようになった時と、見えなくなった時の両方で呼ばれます。見えるようになった時のみに処理が走るように、
isIntersecting
を条件に加えます。 - あとは、監視するターゲット要素を与えてあげるだけです!
ちなみに、どの時点で画面に入ったとするかのタイミング(しきい値)なども、オプションで自由度高くコントロールできてとても便利です。
以上!