JavaScript

【jQuery不要】スクロールしたら固定ヘッダーのCSSを変える - Intersection Observer

最近よく見る、スクロールしたら固定ヘッダーの背景色やサイズ変えたりする方法の実装方法を紹介します。

今回紹介する実装方法は、以下のように今時の技術を使用します。

  • jQueryやライブラリ不要
  • scrollイベントを使わないから処理が軽い(Intersection Observerを使用)

サンプル

こちらにサンプルを用意しました。

See the Pen
Intersection Observer - header scroll to change css
by dadada (@dadada-dadada)
on CodePen.

 

コード

HTMLとCSSは至ってシンプルです。

<header id="js-header">
・・・
</header>

<div  id="js-header-observer">
・・・
</div>
<p>↑この部分がスクロールで画面上部に来たらヘッダーのCSSが変わる</p>

<div>
・・・
</div>
header {
  /* 通常時のスタイル */
}

header[data-js-scroll="true"] {
  /* スクロールした時のスタイル */
}

JavaScriptの記述もかなりシンプルです。

window.addEventListener('DOMContentLoaded', () => {
  // ヘッダーと交差の基準となる要素を定義
  const elmHeader = document.querySelector('#js-header');
  const elmIntersect = document.querySelector('#js-header-observer');
  // 交差した時に実行する関数を定義
  // (ヘッダーにカスタム属性を付ける)
  const doWhenIntersect = entries => {
    elmHeader.setAttribute('data-js-scroll', String(!entries[0].isIntersecting));
  }
  // IntersectionObserverをインスタンス化&実行
  const observer = new IntersectionObserver(doWhenIntersect, {});
  observer.observe(elmIntersect);
});

 

解説

HTMLとCSS

HTMLとCSS側でやることは至ってシンプルです。

ヘッダーとなる要素に id="js-header" を、スクロールの基準となる要素に id="js-header-observer" を付与します。

id="js-header-observer"を指定した要素の下辺が画面上部までスクロールされたら、ヘッダーのCSSが変わります。

 

CSSでは、通常時のヘッダーのスタイルと、スクロール時のヘッダーのスタイルを定義します。

サンプルでは、通常時は data-js-scroll="false" となり、スクロール時には data-js-scroll="true" となります。

JavaScript

一行ずつ解説していきます。

window.addEventListener('DOMContentLoaded', () => {

この中で定義した処理が、HTMLが完全に読み込まれた後に実行されます。

「ページ読み込み後に実行」みたいなイメージです。(この書き方はお約束みたいなものです)

 

// ヘッダーと交差の基準となる要素を定義
const elmHeader = document.querySelector('#js-header');
const elmIntersect = document.querySelector('#js-header-observer');

ヘッダーとなる要素スクロールの基準となる要素を取得しています。

取得さえできればいいので、idなどは自由に書き換えても大丈夫です。

 

// 交差した時に実行する関数を定義
// (ヘッダーにカスタム属性を付ける)
const doWhenIntersect = entries => {
  elmHeader.setAttribute('data-js-scroll', String(!entries[0].isIntersecting));
}

ここでは関数を定義しています。

スクロールの基準となる要素が画面上部まで来た時に実行されます。

引数entriesには、スクロールに関する情報などが渡されます。

ヘッダーの属性値をsetAttribute()で変えており、entries[0].isIntersectingには、真偽値(true or false)が入っています。
基準となる要素より下へスクロールしたらfalse、上へスクロールしたらtrueになります。

さらに細かく解説すると、!を付けてtrue/falseを逆にしています。下へスクロールした時にスタイルを変えるので、属性値に反映させる値は下へスクロールした時にはtrue、上へスクロールした時にはfalseにしたかったのでこのようにしています。
また、String()でboolean型からstring型へ変換しています(真偽値から文字列へ変換)。

 

// IntersectionObserverをインスタンス化&実行
const observer = new IntersectionObserver(doWhenIntersect, {});
observer.observe(elmIntersect);

ここで Intersection Observer を実行します。

new IntersectionObserver(doWhenIntersect, {});でインスタンス化(これを使えるようにする)させ、第一引数には基準となる要素と画面上部が交差した時に実行する関数を指定して、第二引数にはオプションを指定します。
(今回はオプションは不要なので空にしています)

 

observer.observe(elmIntersect); で引数に基準となる要素を与えて実行します。

なので、これまで色々なコードを書いてきましたが、実際に処理を実行しているのはこの箇所のみとなります。

注意点

Intersection ObserverはIEでは使えません。

IEでも使いたい場合はポリフィルが必要です。

https://github.com/w3c/IntersectionObserver/tree/main/polyfill

<script src="path/to/intersection-observer.js"></script>

※自身のjsより前で定義します

まとめ

Intersection Observerはとても便利な技術です。

スクロールイベントでこのようなコードを書いていた方は、これからは是非Intersection Observerを使ってほしいです。
(スクロールイベントだと処理が重くなる傾向などデメリットがあるので)

先程はオプションを空にしています...の記述をしましたが、オプションを指定することで、基準となる要素の画面と交差する基準点を変えたりなど色々カスタマイズできます。

オプション含め、Intersection Observerに関する細かい解説はics.mediaさんがされているので、気になる方は是非見てみてください。