【脱・resizeイベント】window.matchMedia() で実装する軽量なレスポンシブJS処理

レスポンシブ対応のWebサイトを制作していると、「スマホ(SP)の時とパソコン(PC)の時で、JavaScriptの処理を切り替えたい!」という場面によく遭遇しますよね。

そんな時、画面幅の変更を検知するために window.addEventListener('resize', ...) を使って実装していませんか? 実はそれ、以前の記事でご紹介した scroll イベントの時と同じように、サイトのパフォーマンスを落としてしまう原因になるんです。

resizeイベントの罠
resize イベントは、ユーザーがブラウザの幅を少しドラッグして変更するだけで、内部的に何十回・何百回も連続して関数が実行されてしまいます。常に画面幅を計算し続けることになるため、無駄な処理が多くなりブラウザに大きな負担をかけてしまいます。

「特定の画面幅(ブレイクポイント)を跨いだ瞬間だけ、処理を切り替えたい」 そんな要件にピッタリなのが、window.matchMedia() を使ったモダンで軽量なアプローチです!

今回は、CSSのメディアクエリと同じような直感的な書き方で、無駄なくエコにJavaScriptのレスポンシブ対応を行う方法をご紹介します!

実際のデモ動作

See the Pen window-matchMedia by yoshi (@mikanbako) on CodePen.

デモの確認方法
埋め込み画面ではウィンドウ幅の変更が難しいため、ぜひ以下のデモページを開き(別タブで開かれます)、ブラウザの幅を 768px 以上/以下 に伸縮させて実際の動きを確認してみてください!

実装コードの紹介

それでは、実装コードを見ていきましょう。 画面幅(今回は 768px)を境目に、JavaScriptで要素のテキストとクラスを切り替えるシンプルな例です。

【HTML】

切り替えの対象となる要素に js-target というクラスをつけておきます。

<div class="js-target">
  PC表示(769px以上)です💻
</div>

【CSS】

スマホ表示の時に付与する .is-sp クラスに、変更したいスタイルを定義しておきます。

.js-target {
  background-color: #1bb4d4; /* PC時の色 */
}
.js-target.is-sp {
  background-color: #fce621; /* SP時の色 */
}

【JavaScript】

今回のメインとなる window.matchMedia() を使った処理です。

const mql = window.matchMedia('(width <= 768px)');
const target = document.querySelector('.js-target');

const handleMediaQuery = (e) => {
  if (e.matches) {
    target.textContent = 'スマホ表示(768px以下)です📱';
    target.classList.add('is-sp');
  } else {
    target.textContent = 'PC表示(769px以上)です💻';
    target.classList.remove('is-sp');
  }
};

// ブレイクポイントを跨いだ瞬間に発火
mql.addEventListener('change', handleMediaQuery);

// 初期表示時にも判定を実行
handleMediaQuery(mql);

コードの解説・こだわったポイント

今回の window.matchMedia() を使った実装において、実務での運用やパフォーマンス(UX)を向上させるためにこだわったポイントを3つ解説します。

resize イベントとの圧倒的な負荷の違い

導入部分でも触れた通り、window.addEventListener('resize', ...) はブラウザの幅が1ピクセル変わるごとに何度も処理を実行してしまいます。 一方、今回使用した window.matchMedia()change イベントは、指定した条件(今回は768px)を満たしたか・外れたかという「切り替わりの瞬間」にしか発火しません。

ウィンドウ幅を変更している最中の無駄な計算が一切なくなるため、ブラウザへの負荷を最小限に抑え、サイト全体の動作を非常に軽量に保つことができます。

より直感的でモダンな条件式の記述(Media Queries Level 4)

以前のJavaScriptでは、画面幅を判定する際に window.innerWidth <= 768 のように不等号を使って記述するのが一般的でした。一方、従来の window.matchMedia() では (max-width: 768px) と書く必要があり、JavaScriptの条件式に慣れていると少し直感的に分かりづらい部分がありました。

そこで今回の実装では、最新のメディアクエリ(Media Queries Level 4)の構文を採用しています!

// 不等号を使ったモダンなCSSメディアクエリと同じ構文!
const mql = window.matchMedia('(width <= 768px)');

この (width <= 768px) という書き方であれば、従来のJSの if 文と同じような直感的な数式として理解しやすいだけでなく、最新のモダンCSSでのメディアクエリの書き方と完全に一致させることができます。 JavaScriptとCSSで条件式の書き方を統一できるため、コードの可読性や保守性が格段に高まり、後からブレイクポイントを変更する際の手直しも非常にスムーズになります。

【重要】初期読み込み時の表示崩れを防ぐ「初期判定」

レスポンシブ対応で非常によくある落とし穴が、「画面をリサイズした時は切り替わるのに、最初にページを開いた瞬間(リロード時)にデザインが崩れている」という問題です。 change イベントはあくまで「変化した瞬間」にしか動かないため、開いた時点での判定が漏れてしまうのです。

そこで、コードの最後で以下のように手動で関数を1回実行しています。

// ページ読み込み時(初期表示時)にも1回実行しておく
handleMediaQuery(mql);

開いた瞬間のUXにも配慮する
この1行を入れておくことで、ユーザーが最初にサイトを訪れた瞬間から、そのデバイスの画面幅に合わせた正しいJavaScriptの処理が最初からバッチリ適用されます。ユーザーに一瞬でも崩れた画面を見せないための、大切なUX(ユーザー体験)への配慮です。

補足:参考リンク

今回使用した window.matchMedia() について、より詳しい仕様やその他の活用方法を知りたい方は、ぜひ以下の公式ドキュメントも参考にしてみてくださいね。

・MDN: Window.matchMedia()
・Can I Use: window.matchMedia

まとめ

今回は、resize イベントを使わずに window.matchMedia() を使用して、無駄な処理を徹底的に省いたエコなレスポンシブJavaScriptを実装する方法をご紹介しました。

以前のスクロール判定(Intersection Observer)に続き、今回のリサイズ判定でも「動けば何でも良いわけではなく、ブラウザの負荷(パフォーマンス)を常に意識する」というアプローチを取り入れました。

ユーザーがどんなデバイスで、どのようにブラウザを操作しても、常に軽快でストレスのないサイトを提供できるエンジニアでありたいと考えています。

こうした裏側の小さな工夫の積み重ねが、最終的にサイト全体の品質やユーザーの満足度(UX)に直結してくるはずです。 これからも、スマートで無駄のない洗練されたコード設計を意識して、日々の作品作りと学習に励んでいきます!

最後まで読んでいただき、ありがとうございました!

Prev
Next