本記事ではこちらのデモサイトのように、スクロールに合わせて左側ナビゲーションの背景色を変更する実装を解説しています。
記事のポイントはこちら。
・Vanilla JavaScriptで実装
・図解を交えてわかりやすく説明
・Web制作学習中、実務初心者の方におすすめ
実務でもよく使う実装なので、ぜひ本記事を通してマスターしてください!
目次
この記事でわかること
この記事を読むことで、次の3つのことが理解できます。
「IntersectionObserverの基本はもうOK!」という方は、こちらからコードをどうぞ。
・スクロールに合わせて背景色を変更する理由
・IntersectionObserverの基本的な使い方
・スクロールに合わせて背景色を変える具体的な実装方法
なぜスクロールに合わせて背景色を変える?
UX(ユーザーエクスペリエンス)を向上させるためです。
具体的には、以下の3つ。
・LPなどの縦に長いコンテンツを閲覧する際に、今どこを見ているのかを分かりやすくする
・ページ内リンクと併せて実装することで、見たい箇所・見返したい箇所にすぐ戻ることができる
・静的ページにも動きを出すことができる
コードだけ欲しい方はこちら
<div class="nav-item">
<a href="#section1" class="nav-item__link">セクション1</a>
</div>
<div class="nav-item">
<a href="#section2" class="nav-item__link">セクション2</a>
</div>
<div class="nav-item">
<a href="#section3" class="nav-item__link">セクション3</a>
</div>
<div class="nav-item">
<a href="#section4" class="nav-item__link">セクション4</a>
</div>
<section class="section" id="section1"></section>
<section class="section" id="section2"></section>
<section class="section" id="section3"></section>
<section class="section" id="section4"></section>
.nav-item__link{
background-color: #f9f9f9;
transition: all .3s;
font-weight: 600;
}
.nav-item__link.current{
color: #fff;
background-color: #2b4d70;
text-shadow: 0 0 5px rgba(0,0,0,0.3);
}
document.addEventListener('DOMContentLoaded', () => {
//セクションに付与したidをキーとするオブジェクトを定義
const sectionTitleMap = {
section1: 'セクション1',
section2: 'セクション2',
section3: 'セクション3',
section4: 'セクション4',
}
//監視対象(sections)と変更を加える要素(navLinks)の定義
const sections = document.querySelectorAll('.section');
const navLinks = document.querySelectorAll('.nav-item__link');
//IntersectionObserverで使用するコールバック関数の定義
const bgChange = (entries) => {
//IntersectionObserverのentries配列から、isIntersectiong,targetを分割代入
entries.forEach(({ isIntersecting, target }) => {
if (!isIntersecting) return; //交差していない場合は何もしない
//targetは監視対象(各.sectionのこと)
const targetId = target.id;
//sectionTitleMapオブジェクトのキーに現在交差しているidの値を取得、代入
const currentTitle = sectionTitleMap[targetId];
navLinks.forEach((link) => {
const isCurrent = link.textContent === currentTitle;
//nav-item__linkに設定されているテキストとtargetのテキストが等しい場合、.currentクラスを付与
link.classList.toggle('current', isCurrent);
});
})
}
//IntersectionObserverで使用するオプション
const changebgOptions = {
root:null,
rootMargin: '0px 0px -50% 0px', //viewportの半分まで来たら交差する判定
threshold: 0,
}
//IntersectionObserverの初期化
const navbgChangeObserver = new IntersectionObserver(bgChange,changebgOptions);
//各セクションの監視を開始
sections.forEach(section=>{
//IntersectionObserverのメソッドobserver()で監視が可能
navbgChangeObserver.observe(section);
})
});
実装の流れとコード解説
実装の流れ
STEP
HTML
- 監視対象となる<section>タグに任意のidとクラス名を付与
- 背景色を変更するナビゲーションアイテムの用意
STEP
CSS
- ナビゲーションアイテムの背景色変更前・変更後のスタイルを定義
STEP
JavaScript
- 監視対象要素(<section>)とナビゲーションアイテム(“.nav-item__link”)のDOMを取得
- <section>に指定したid名をキー、ナビゲーションアイテムのテキストを値とするオブジェクトを定義
- 以下の役割を持つコールバック関数の定義
– 交差している監視対象要素(<section>)のid名を取得
– 取得したid名を上記オブジェクトのキーに設定し、値を取り出す
– 取得した値とナビゲーションアイテムのテキストを比較し、等しい場合に”current”を付与 - optionの定義
– viewportの半分まで監視対象要素が来たら交差判定するよう、rootMarginのbottomの値に-50%を指定 - IntersectionObserverのインスタンス化
- <section>の監視を開始
コード解説
今回実装したコードを図解すると次のようになります。
コードに付与したコメントを参考としてください。

document.addEventListener('DOMContentLoaded', () => {
//セクションに付与したidをキーとするオブジェクトを定義
const sectionTitleMap = {
section1: 'セクション1',
section2: 'セクション2',
section3: 'セクション3',
section4: 'セクション4',
}
//監視対象(sections)と変更を加える要素(navLinks)の定義
const sections = document.querySelectorAll('.section');
const navLinks = document.querySelectorAll('.nav-item__link');
//IntersectionObserverで使用するコールバック関数の定義
const bgChange = (entries) => {
//IntersectionObserverのentries配列から、isIntersectiong,targetを分割代入
entries.forEach(({ isIntersecting, target }) => {
if (!isIntersecting) return; //交差していない場合は何もしない
//targetは監視対象(各.sectionのこと)
const targetId = target.id;
//sectionTitleMapオブジェクトのキーに現在交差しているidの値を取得、代入
const currentTitle = sectionTitleMap[targetId];
navLinks.forEach((link) => {
const isCurrent = link.textContent === currentTitle;
//nav-item__linkに設定されているテキストとtargetのテキストが等しい場合、.currentクラスを付与
link.classList.toggle('current', isCurrent);
});
})
}
//IntersectionObserverで使用するオプション
const changebgOptions = {
root:null,
rootMargin: '0px 0px -50% 0px', //viewportの半分まで来たら交差する判定
threshold: 0,
}
//IntersectionObserverの初期化
const navbgChangeObserver = new IntersectionObserver(bgChange,changebgOptions);
//各セクションの監視を開始
sections.forEach(section=>{
//IntersectionObserverのメソッドobserver()で監視が可能
navbgChangeObserver.observe(section);
})
});
まとめ
・スクロールに合わせてナビゲーションの背景色を変更するのはUX向上のため
・IntersectionObserverを使用し、各セクションとviewportの交差を判定
・交差した際にナビゲーションの背景色を変更するクラス(.curent)を付与