JavaScriptで目次のカレント表示をさせる方法(Intersection Observer API)

schedule Published
Category folderJumble
format_list_bulleted Contents

このブログの記事にある目次は、要素位置と現在のスクロール量を、スクロールの度に計算してカレント表示(現在地ハイライト)していたが、Intersection Observer API(交差オブザーバー API) という便利なものがあるのを知ったので、ブログの目次機能を作り直してみた。

Intersection Observer APIとは

Intersection Observer API(交差オブザーバー API )は、監視対象の要素(ターゲット要素)ビューポートまたは指定された要素(root要素)交差した際に、それを検知してコールバックを呼び出せる。

交差の検知は、交差率というターゲット要素がどのくらい表示されたかを閾値(0.0~1.0)で指定する。まだ交差していない状態で検知したい場合は、root要素を拡げるrootマージン(px値 or パーセント値)を利用することで検知できる。

Intersection Observer APIを使えば、スクロールやリサイズの度にイベントを発生させて、現在のスクロール位置とターゲット要素との差分を再計算する必要がなくなる!

Intersection Observer APIの使い方

① Intersection Observer(交差オブザーバー)の作成

コンストラクター関数で、オプションで指定した条件でターゲットが交差する度に、コールバック関数を渡すことでインスタンスを生成する。

const options = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '0px',
  threshold: 1.0
}

const observer = new IntersectionObserver(callback, options);

settingsオプションについて

  • root

    ターゲットが見えるかどうかを確認するためのビューポートを指定。指定されなかった場合、または null の場合は既定でブラウザーのビューポートとなる。

  • rootMargin

    root要素の範囲を拡大・縮小するマージンを設けることができる。マージンはpx値かパーセント値で指定。'10px 20px 30px 40px' の場合、上, 右, 下 ,左 のマージンで、CSSと同じような形で指定できる。

  • threshold

    ターゲット要素がどのくらい見えた場合にコールバックを実行するかを指定する。既定値は0で1pxでも見えるとコールバックを実行する。1つ以上の数値を指定でき、 0.5の場合は50%見えたとき、[0.1, 0.25, 0.5, 1]と配列で複数を指定した場合だと、10%, 25%, 50%, 100%見えたときにコールバックを実行する。

② 監視対象を指定して、作成したオブザーバーに監視させる

const target = document.querySelector('#hogehoge');
observer.observe(target);

③ コールバック関数を作成する

コールバックは、IntersectionObserverEntry オブジェクトの配列(entries)オブザーバー(observer)を受け取る。

callback = (entries, observer) => {
  entries.forEach((entry) => {
    ︙
  });
};

tips_and_updatesIntersectionObserverEntryについて

IntersectionObserverEntryはIntersection Observer APIに用意されているインターフェイスで、各ターゲット要素と各ターゲットの交差状態を表す。このIntersectionObserverEntryのインスタンスが、コールバックにentriesの引数で渡される。
決まりごとなので、entriesで渡されると覚えておく。

tips_and_updatesIntersectionObserverEntryのプロパティ

  • boundingClientRect

    ターゲットのバウンディングボックス

  • intersectionRatio

    ターゲットがどのくらい見えているか、0.0 から 1.0 の数値。
    ターゲットの面積が0の場合でも、0か1を返す。

  • intersectionRect

    ターゲットの交差している部分のバウンディングボックス

  • isIntersecting

    target 要素が交差状態に遷移したか (true) または交差状態から脱したか (false) のブール値。

  • rootBounds

    root要素のバウンディングボックス

  • target

    そのままターゲット要素(element)。

  • time

    文書の作成時刻を基準とする交差状態が発生した時刻

これで事前の下調べは完了した。ブログの目次のカレント表示機能を書き直して変更した。

Intersection Observer API を使った目次のカレント表示

ブログには実装済みだが、CODEPENでサンプルも書いてみた。

おわりに

目次のカレント表示は Intersection Observer API を使うことによって、従来のスクロールの度にイベント発火する必要はなくなった。
ブログ記事は、上にスクロールした時、下にスクロールした時、それぞれに余計なスクロールエフェクトをつけているために、その部分はスクロールの度にイベント発火している(泣)。

画面と交差したらアニメーションさせるなど、使う機会は多そうだ。