ブラウザーと DOM の寸法を測定する

最終更新: 2026-01-08 10:38:14 +0800 +0800
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

画面、ブラウザーウィンドウ、ビューポート、ドキュメント、要素は異なる測定上の問いに答えるため、ブラウザー API は複数の座標系を公開します。したがって、名前だけで API を選ぶと、スクロールバー、丸め、スクロールに関するエラーが発生する可能性があります。

ウィンドウ、画面、ビューポートの測定 #

API測定対象
window.innerWidth, innerHeightレイアウトビューポート。描画されたクラシックスクロールバーを含む
window.outerWidth, outerHeightブラウザーウィンドウの外側の寸法
screen.width, screen.heightCSS ピクセル単位の画面寸法
screen.availWidth, screen.availHeightオペレーティングシステムが予約した領域を除く画面領域
document.documentElement.clientWidth, clientHeightクラシックスクロールバーを除くレイアウトビューポート

CSS ピクセルは論理単位です。高密度ディスプレイでは、1 CSS ピクセルが複数のデバイスピクセルをカバーするため、screen.width はパネルの物理ピクセル数と必ずしも一致しません。

outerWidth と outerHeight にはブラウザーのクロームが含まれます。内側の寸法との差は、ウィンドウ装飾、タブ、ツールバー、ディスプレイのスケーリングに依存するため、ページレイアウトを制御するために使用すべきではありません。

js
const viewport = {
  width: document.documentElement.clientWidth,
  height: document.documentElement.clientHeight,
};

クラシックスクロールバーを除外する必要がある計算では、ルート要素の client 寸法を使用します。オーバーレイスクロールバーはレイアウト幅を消費しないため、innerWidth と clientWidth の差はプラットフォームに依存します。

レイアウトビューポートとビジュアルビューポート #

レイアウトビューポートは、ページレイアウトで使用される包含ブロックを確立します。ビジュアルビューポートは、ピンチズームまたは画面キーボードによって遮られていない領域が変化した後に、現在見えている部分です。対応ブラウザーでは、window.visualViewport が width、height、scale、offsetLeft、offsetTop を公開します。

js
const viewport = window.visualViewport;

viewport?.addEventListener("resize", positionOverlay);
viewport?.addEventListener("scroll", positionOverlay);

可視領域に追従する必要があるオーバーレイには、これらのイベントを使用します。通常のドキュメントレイアウトは CSS とレイアウトビューポートを引き続き使用すべきです。ビジュアルビューポートイベントに応じてページ全体を移動すると、ブラウザーのスクロールと競合する可能性があります。

要素ボックスの測定 #

API含まれる領域精度
clientWidth, clientHeightコンテンツとパディング。境界線とスクロールバーを除く整数
scrollWidth, scrollHeightスクロールなしで必要な最小のコンテンツとパディングの範囲整数
offsetWidth, offsetHeight描画されたスクロールバーを含む境界ボックス整数
getBoundingClientRect()ビューポート座標の境界ボックスジオメトリ小数

CSS ボックスを作成しないインライン要素では、clientWidth と clientHeight は 0 です。ルート要素では、これらはビューポートを表します。過去の quirks mode では body 要素がビューポート測定に参加することがありますが、標準モードのドキュメントでは document.documentElement を使用してください。

スクロール可能なオーバーフローにより、scrollHeight または scrollWidth が対応する client 寸法を超えることがあります。

js
function hasVerticalOverflow(element) {
  return element.scrollHeight > element.clientHeight;
}

疑似要素のコンテンツがスクロール寸法に寄与する場合があります。整数値 API ではサブピクセルレイアウトが丸められるため、小数のジオメトリが重要な場合は getBoundingClientRect() を使用します。

座標系とスクロール #

getBoundingClientRect() はビューポートを基準とした座標を返します。

js
const rect = element.getBoundingClientRect();
console.log(rect.left, rect.top, rect.width, rect.height);

ビューポート座標をドキュメント座標に変換するには、現在のスクロールオフセットを加算します。

js
const documentTop = rect.top + window.scrollY;
const documentLeft = rect.left + window.scrollX;

変換は返される矩形に影響します。結果は変換後の境界ボックスを含む最小の軸平行ビューポート矩形であり、変換前のレイアウト寸法ではありません。

正しいタイミングで測定する #

ジオメトリは、フォント、画像、スタイルシート、アプリケーションデータの読み込み後に変化することがあります。レイアウトに影響する依存関係が利用可能になった後に測定します。後続のサイズ変更に反応する必要があるコードでは ResizeObserver を使用します。

js
const observer = new ResizeObserver(([entry]) => {
  const { inlineSize, blockSize } = entry.contentBoxSize[0];
  console.log({ inlineSize, blockSize });
});

observer.observe(element);

ジオメトリの読み取りによって、ブラウザーが保留中のスタイルとレイアウト処理を完了させることがあります。アニメーションコードでは読み取りを先にまとめ、書き込みを後にまとめてください。レイアウトの読み取りとスタイル変更を交互に行うと、同期レイアウトが繰り返し発生する可能性があります。

requestAnimationFrame はレンダリングフェーズを選択しますが、レイアウトの読み取りを無料にはしません。必要なすべてのジオメトリを先に読み取り、次の状態を計算し、その後にスタイルまたは DOM の書き込みを別のバッチとして適用します。

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)