【JavaScript】画面サイズをリアルタイムで取得する方法

レスポンシブ対応や、画面幅に応じた表示切り替えのために、JavaScriptで画面サイズをリアルタイムに取得したい場面はよくあります。

基本は window.innerWidth / window.innerHeightresize イベントですが、「どのプロパティを使うか」「resizeをそのまま使うと重くなる」といったつまずきポイントがあります。この記事では、用途別の使い分けと効率的な監視方法までそのまま動くコードで解説します。

この記事の結論:画面サイズは window.innerWidth / window.innerHeight で取得し、変化の監視は resize イベントで行います。ただし resize は高頻度で発火するためthrottle/debounceで間引くのが必須。ブレークポイント判定だけなら matchMedia、要素単位の監視なら ResizeObserver が効率的です。
スポンサーリンク

画面サイズを取得する(基本)

現在のビューポート(表示領域)のサイズは window.innerWidthwindow.innerHeight で取得できます。要素に表示してみましょう。

HTML
<div id="size">幅: 0px / 高さ: 0px</div>
JavaScript:現在のサイズを表示
function showSize() {
  const el = document.getElementById("size");
  el.textContent = `幅: ${window.innerWidth}px / 高さ: ${window.innerHeight}px`;
}

showSize(); // 初期表示(読み込み時点のサイズ)

これで読み込み時点のサイズが表示されます。あとはサイズ変更を監視すればリアルタイムになりますが、その前に「どのプロパティを使うべきか」を整理しておきます。

取得プロパティの使い分け

「画面サイズ」と一口に言っても、対象によってプロパティが異なります。主なものは次のとおりです。

プロパティ 取得できるサイズ スクロールバー
window.innerWidth / innerHeight ビューポート(表示領域) 含む
documentElement.clientWidth / clientHeight ビューポート(表示領域) 除く
window.outerWidth / outerHeight ブラウザウィンドウ全体(ツールバー込み)
screen.width / height デバイスの物理画面
スクロールバーのズレに注意:window.innerWidthスクロールバーを含む幅、document.documentElement.clientWidth含まない幅です。CSSの @media (max-width: ...) は基本的にスクロールバーを含まない幅で判定するため、innerWidth とCSSのブレークポイントが数px〜十数pxズレることがあります。CSSと厳密に揃えたいときは clientWidth を使ってください。

なお、高解像度(Retina)ディスプレイの判定には window.devicePixelRatio(CSSピクセルに対する物理ピクセルの比率。Retinaなら2以上)を使います。

リサイズをリアルタイムで監視する(間引き必須)

サイズ変更の監視には resize イベントを使います。ただし resizeドラッグ中に1秒間で何十回も発火します。重い処理を直結すると一気にカクつくため、throttle(一定間隔に1回)で間引きます。

JavaScript:throttleで間引いて監視
// 一定間隔に1回だけ実行する throttle
function throttle(fn, interval) {
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last >= interval) {
      last = now;
      fn(...args);
    }
  };
}

// 200msに1回までサイズを更新(ドラッグ中も追従しつつ軽い)
window.addEventListener("resize", throttle(showSize, 200));

ドラッグ中も追従させたいなら throttle、「リサイズが止まってから一度だけ」でよいなら debounce が向いています。2つの違いと実装はdebounceとthrottleの違いと実装方法で詳しく解説しています。

ブレークポイント判定は matchMedia が効率的

「モバイル幅かどうか」だけを知りたいなら、resize で毎回幅を比較するより matchMediachange イベントが効率的です。境界をまたいだ瞬間だけ発火するため、無駄な処理が走りません。

JavaScript:matchMediaでブレークポイント判定
const mq = window.matchMedia("(max-width: 767px)");

function handleChange(e) {
  if (e.matches) {
    console.log("モバイル幅");
  } else {
    console.log("デスクトップ幅");
  }
}

handleChange(mq);                          // 初期判定
mq.addEventListener("change", handleChange); // 境界をまたいだ時だけ発火

ウィンドウ幅の条件でページを切り替える具体例はウィンドウサイズの条件でページをリロードする方法も参考になります(連続リロードの罠も解説しています)。

特定要素のサイズ監視は ResizeObserver

ウィンドウ全体ではなく特定の要素のサイズ変化を監視したいときは、resize ではなく ResizeObserver を使います。サイドバーの開閉やコンテンツ量の変化など、ウィンドウサイズと無関係な変化も拾えます。

JavaScript:ResizeObserverで要素を監視
const box = document.getElementById("box");

const observer = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const { width, height } = entry.contentRect;
    console.log(`要素サイズ: ${Math.round(width)} x ${Math.round(height)}`);
  }
});

observer.observe(box); // 監視開始(不要になったら observer.disconnect())

要素サイズに応じてレイアウトを揃える実践例は要素の高さを揃える方法で扱っています。

モバイルで innerHeight が変わる問題(visualViewport)

スマホでは、アドレスバーの表示・非表示で window.innerHeight が変動します。これが「100vh にすると画面からはみ出す」問題の原因です。実際に見えている領域を正確に取りたいときは window.visualViewport を使います。

JavaScript:visualViewportで見える領域を取得
// 対応ブラウザでのみ実行(?. で安全に)
window.visualViewport?.addEventListener("resize", () => {
  const vv = window.visualViewport;
  console.log(`表示領域の高さ: ${Math.round(vv.height)}px`);
});

よくある質問(FAQ)

QJavaScriptで画面サイズをリアルタイムに取得するには?
Awindow.innerWidth / window.innerHeight が現在のビューポートサイズを返し、resize イベントで変化を監視できます。resize は高頻度で発火するため、throttle/debounceで間引くのが前提です。
QinnerWidth と clientWidth と screen.width の違いは?
Awindow.innerWidth はスクロールバーを含むビューポート幅、document.documentElement.clientWidth含まない幅(CSSの@mediaと一致しやすい)、screen.width はデバイスの物理画面幅です。通常のレスポンシブ対応にはビューポート幅を使います。
Qモバイルとデスクトップを判定するには?
Awindow.matchMedia("(max-width: 767px)").matches で判定するのが確実です。CSSのブレークポイントと同じ条件で書けるうえ、change イベントで境界をまたいだ時だけ処理できます。User-Agent判定より正確なレスポンシブ対応になります。
Qウィンドウ全体ではなく特定要素のサイズ変化を監視するには?
AResizeObserver を使います。observer.observe(要素) で監視を開始し、コールバックの entry.contentRect から幅・高さを取得できます。ウィンドウサイズと無関係な要素の変化も検知できるのが利点です。

まとめ

画面サイズの取得は window.innerWidth / innerHeight が基本で、スクロールバーを除いた値が必要なら documentElement.clientWidth を使い分けます。リアルタイム監視は resize イベントですが、throttle/debounceでの間引きが必須です。

目的が「ブレークポイント判定」なら matchMedia、「特定要素の監視」なら ResizeObserver の方が効率的です。モバイルで見える領域を正確に扱いたいときは visualViewport も覚えておくと役立ちます。