特定のスクリーンサイズを起点に JavaScript で何かするための方法

特定の画面幅を基準に処理を分ける方法を3つ紹介します


Window resize event を利用する

まず紹介するのは Window resize event を使った方法です。 Window: resize event - Web APIs | MDN

DEMO

codepen.io

実行頻度に注意する

最も古くから利用されてきた方法で、どのブラウザでも動かすことができます。 EventTarget.addEventListener() を使って Window resize event に関数を紐付けます。 ウィンドウのサイズが変更する度に関数を実行して「今のウィンドウサイズ」を window.innerWidth などで取得して処理を実行します。

window.addEventListener('resize', () =>{
  el.innerHTML = window.innerWidth > 1000 ? '1000px 以上' : '1000px 未満';
});

実際に実務で利用する際にはそのまま関数を紐付けることはないでしょう。 throttledebounce といった手法を使い、一定時間中1回だけ実行するようにしたり、一定時間後に 1回だけ実行するようにして処理を間引くことで過剰に実行されるのを制限します。 次項でその方法を紹介します。

Window resize event + throttleを利用する

上記であげたように、resize イベントに直接ハンドラーを紐付けると過剰に実行されていまいます。 実行回数を制限するために throttle を使って実行回数を制限してみます。

DEMO

codepen.io

  • throttle 処理は自作してもよいですが、ユーティリティライブラリ lodash) や throttle-debounce というシンプルなモジュールが公開されているのでこれを活用してしまうのが楽でよいでしょう。

今回は throttle-debounce を使った例を示します。 throttle-debounce - npm

throttle() の第一引数には処理を間引く時間を指定します。 ここで指定した時間内に複数回実行されても1度だけしか実行されなくなります。

const checkWidth = throttle(10, () => {
  el.innerHTML = window.innerWidth > 1000 ? '1000px 以上' : '1000px 未満';
});
window.addEventListener("resize", checkWidth);

Resize Observer を利用する

ResizeObserver - Web API | MDN HTML要素を監視して何かする Observer 系 API の一つ HTML要素のサイズを監視することができます。 html や body 要素を監視することで上の方法と同じようなことができます。

DEMO

codepen.io

const resizeObserver = new ResizeObserver(entries => {
  for (let entry of entries) {
    el.innerText = entry.contentRect.width >= 1000 ? '1000px 以上' : '1000px 未満';
  }
});
resizeObserver.observe(document.querySelector('html'));

new ResizeObserver で第一引数にリサイズ時のコールバック関数を指定してインスタンスを作成し、resizeObserver.observe で DOM を指定します。

コールバック関数では ResizeObserverEntry の配列を受け取れます。 ResizeObserverEntry には 以下のような値が含まれています。

  • borderBoxSize ... border を含めたコンテンツのサイズ (inlineSize が横幅, blockSize が縦幅のよう)
  • contentBoxSize ... border, padding を含めいないコンテンツのサイズ
  • contentRect ... コンテンツの矩形情報を取得する
  • devicePixelContentBoxSize ... 実 pixel のコンテンツのサイズ(Retina Display だったら 2倍になる)

Resize Observer は比較的新しいAPIのため IE11 では使うことができません。 IE11 で動かしたい場合は polyfill を適用することで使うことができます。

resize-observer-polyfill - npm

また、こちらで画面幅を監視する場合、 resize event と実行タイミングは同じなので、 resize event と同様に実行回数を間引く処理を加えたほうがよいでしょう。


mediaQueryList を利用する

最後に、 mediaQueryList を使った方法を紹介します。

DEMO

codepen.io

window.matchMedia.matches を利用すると第一引数で渡したメディアクエリ文字列に一致するかどうかを真偽値で返してくれます。

const mediaQueryList = window.matchMedia('(min-width: 1000px)');
if(mediaQueryList.matches) {
  /* ビューポートの幅が 1000 ピクセル以上の場合 */
}

window.matchMedia で作成される mediaQueryListaddEventListener を持っていて、 change イベントを購読することでメディアクエリ文字列に一致したときの処理をコールバック関数に書くことができます。

const mediaQueryList = window.matchMedia('(min-width: 1000px)');
mediaQueryList.addEventListener('change', (event) => {
  console.log(event.matches ? 'マッチした!' : 'マッチしてない!');
}, false);

先述で挙げた2つの方法は画面のリサイズに対して反応するため、判定基準となる幅以外の時や縦のリサイズにも反応していました。

mediaQueryList を使った方法なら境界値をまたいだ時だけ処理を実行することが可能です。

こちらは今のメジャーブラウザなら問題なく使うことができるようになっています。

但し MediaQueryList.addEventListener は元々 mediaQueryList.addListener という名前で実装されていた経緯から、現時点で IE や Safari などでは MediaQueryList.addListener しか実装されていないため、これらのブラウザで利用する場合は MediaQueryList.addEventListener の存在チェックを行った上でどちらのメソッドを利用するか決める必要があります。 MediaQueryList.addListener() - Web APIs | MDN