【JavaScript】ウィンドウサイズの条件でページをリロードする方法|matchMediaで安全に・連続リロードの罠も解説

「画面幅が一定以下になったらページを読み込み直したい」という要件は、レスポンシブ対応の現場でときどき出てきます。ただしやり方を間違えると、ページが延々とリロードを繰り返して操作不能になります。この記事では、安全な実装とそもそもリロードすべきかどうかまで整理します。

この記事の結論:resize イベントで直接 location.reload() を呼ぶのは連続リロードの原因になり危険です。「特定の幅を跨いだ時に1回だけ」なら window.matchMedia()change イベントを使います。そもそもレイアウト調整が目的ならCSSや動的な再描画で済むことが多く、フルリロードは最終手段です。
スポンサーリンク

まず知っておきたい:resize + reload の罠

次のコードは一見動きそうですが、重大な問題があります。

NG: 連続リロードを起こす書き方
window.addEventListener("resize", () => {
  if (window.innerWidth <= 800) {
    location.reload(); // 危険!
  }
});
なぜ危険か:resize イベントは、ウィンドウをドラッグしている間1秒に何十回も発火します。幅が800px以下の状態では発火のたびに location.reload() が呼ばれ、ページがリロードを繰り返して操作できなくなります。しきい値の近くで少し動かすだけでも延々と読み込み直しが走ります。

正攻法:matchMedia の change イベント(推奨)

「特定の幅を跨いだ瞬間に1回だけ」処理したいなら、window.matchMedia() を使います。CSSのメディアクエリと同じ条件を指定でき、条件の一致状態が変わったとき(境界を越えたとき)だけ change イベントが発火します。ピクセル単位では発火しないので、連続リロードになりません。

OK: 800pxを跨いだ時だけリロード
const mq = window.matchMedia("(max-width: 800px)");

mq.addEventListener("change", (e) => {
  // e.matches: 条件に一致した(800px以下になった)瞬間だけ true
  if (e.matches) {
    location.reload();
  }
});
change「800pxを超える ⇄ 800px以下」の切り替わり時だけ発火します。800px以下のまま小刻みにリサイズしても再発火しないため、resize 直叩きのような暴走は起きません。上下どちらの方向の変化も検知したいときは e.matches の値で分岐します。

どうしても resize を使うなら debounce する

幅と高さの両方を細かく見たいなど、resize を使わざるを得ない場合は、debounce(間引き)で「リサイズが止まってから1回だけ」実行します。ただししきい値以下のたびにリロードが走る性質は残るため、可能なら matchMedia を優先してください。

debounce でリサイズ終了後に判定
let timer;
window.addEventListener("resize", () => {
  clearTimeout(timer);
  timer = setTimeout(() => {
    if (window.innerWidth <= 800 || window.innerHeight <= 600) {
      location.reload();
    }
  }, 300); // 300ms 操作が止まったら実行
});

そもそもリロードが必要か見直す

「レイアウトを切り替えたい」だけなら、フルリロードは不要なことがほとんどです。次の方法のほうが速く、状態も保てます。

  • CSSメディアクエリ:見た目の出し分けはCSSだけで完結する(JS不要)
  • 動的な再描画:必要な部分のDOMだけ作り直す(ページ全体は再読み込みしない)
  • ResizeObserver:ウィンドウではなく特定の要素のサイズ変化を監視したいとき
リロードは状態を失います:location.reload()スクロール位置・入力中のフォーム・アプリの状態をすべてリセットします。どうしてもリロードが必要なら、フォーム入力をローカルストレージに保存するなどして、再読み込み後に復元する配慮をしましょう。
フルリロードが妥当なのは、PC用とモバイル用でページの構造そのものが大きく異なり、動的に切り替えられないような限られたケースです。その場合も、初回読み込み時に幅を判定して出し分ける設計のほうが安全なことが多いです。

よくある質問(FAQ)

Qresize イベントで reload するとどうなりますか?
Aresize はドラッグ中に何十回も発火するため、条件を満たす間 location.reload() が連続で呼ばれ、ページがリロードを繰り返して操作不能になります。「幅を跨いだ時だけ」なら matchMediachange を使ってください。
Q特定の幅になった時だけ処理するには?
Awindow.matchMedia("(max-width: 800px)") を作り、change イベントを監視します。e.matchestrue になった瞬間が「800px以下になった時」です。CSSのメディアクエリと同じ条件指定で、境界を跨いだ時だけ発火します。
QmatchMedia と resize はどう使い分けますか?
Aブレークポイントの跨ぎを検知するなら matchMedia連続的なサイズ変化に追従したいなら resize(要 debounce)です。リロード用途では暴走しない matchMedia が安全です。
Qリロードせずにレイアウトを変えたいのですが?
A多くの場合CSSメディアクエリで出し分けできます。JavaScriptで構造を変える必要があっても、必要な部分のDOMだけ動的に再描画すれば、スクロール位置や入力を保ったままレイアウトを切り替えられます。

まとめ

ウィンドウサイズの条件でリロードする方法のポイントを整理します。

  • resize で直接 location.reload()連続リロードの罠
  • 「幅を跨いだ時だけ」は matchMediachange(推奨)
  • resize を使うなら debounce で間引く
  • レイアウト変更はCSS・動的再描画で済むことが多い(リロードは最終手段)
  • リロードは状態を失う → 必要ならlocalStorageで復元

関連として、ページをリロードする方法要素の高さを揃える方法(ResizeObserver)フォーム入力をローカルストレージに保存する方法もあわせて確認すると、リサイズ・再読み込み周りの実装に強くなれます。