MENU

【JavaScript】スクロールに合わせてナビゲーションの背景色を変更!IntersectionObserverで簡単実装!

本記事ではこちらのデモサイトのように、スクロールに合わせて左側ナビゲーションの背景色を変更する実装を解説しています。

記事のポイントはこちら。

・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)を付与

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