要素の高さ・幅の「どれを測るか」
同じ「幅・高さ」でも、境界や余白の扱いで数値が変わります。どの API を使うかで意味が違うため、まず“何を含めたいか”を決めましょう。ここが重要です:枠線(border)や余白(padding)を含めるか、スクロール可能な中身の“総サイズ”が欲しいかで、正しい測り方が変わります。
よく使う3つの数値(offset・client・scroll)
offsetWidth / offsetHeight(枠線と内側まで)
「視覚上の箱サイズ」を手早く知るときに使います。border と padding を含み、margin は含みません。
<div id="box" style="margin:16px; padding:8px; border:4px solid; width:200px; height:100px;"></div>
<script>
const box = document.getElementById("box");
console.log(box.offsetWidth, box.offsetHeight); // 200(px) + padding + border を含む実サイズ
</script>
HTMLここが重要です:画面に見える“箱の大きさ”が欲しいなら offset が最短です。余白(margin)は隣接関係なので含まれない点に注意。
clientWidth / clientHeight(コンテンツ領域)
padding は含み、border は含みません。スクロールバーの幅は除外されます。
console.log(box.clientWidth, box.clientHeight); // 見出しや本文の“内側”の大きさ
JavaScriptここが重要です:内容領域のサイズ(CSS の content+padding)が欲しいときは client。レイアウトで中身をぴったり埋めたいときに便利です。
scrollWidth / scrollHeight(中身の“総”サイズ)
溢れてスクロールする分も含めた、コンテンツ全体の大きさです。
console.log(box.scrollWidth, box.scrollHeight); // 目に見える以上に大きい場合、その総量
JavaScriptここが重要です:折りたたみコンテンツをアニメーションする際、最大高さの目安に scrollHeight を使うのが定石です。
getBoundingClientRect(画面座標で正確に測る)
位置とサイズをまとめて取得
スクロール位置やズームを含めた「画面上の位置・サイズ」を返します。小数点も扱い、精度が高いです。
<div id="target" style="position:relative; left:10px; width:180px; height:90px;"></div>
<script>
const rect = document.getElementById("target").getBoundingClientRect();
console.log(rect.left, rect.top, rect.width, rect.height); // 画面基準の座標とサイズ
</script>
HTMLここが重要です:ポップアップの位置合わせ、クリック判定の当たり判定、ビューポートとの交差計測など“座標系”が必要な場面は rect 一択です。
CSS と箱モデルの影響(box-sizing と単位の違い)
box-sizing の違いで「width の意味」が変わる
- content-box(初期値):width は“コンテンツ幅”。padding と border を足すと見える幅が増える。
- border-box:width は“見える箱幅”。padding や border を含んだ値になる。
<div id="a" style="box-sizing:content-box; width:200px; padding:20px; border:4px solid;"></div>
<div id="b" style="box-sizing:border-box; width:200px; padding:20px; border:4px solid;"></div>
<script>
console.log(a.offsetWidth, b.offsetWidth); // a は 200+20+20+4+4, b は 200(ほぼ)
</script>
HTMLここが重要です:数値の解釈は box-sizing 依存。プロジェクト全体で border-box を採用すると、視覚上の幅と CSS の指定が揃って混乱が減ります。
getComputedStyle で“最終的な見え方”を読む
const cs = getComputedStyle(a);
console.log(cs.width, cs.paddingLeft, cs.borderLeftWidth); // 単位付き文字列で返る
JavaScriptここが重要です:element.style は“インライン指定”しか返しません。外部 CSS まで含めた確定値は getComputedStyle を使いましょう。
計測のタイミングと“測れない”状態への対処
DOM が描画されてから測る
画像やフォントが未読み込みだとサイズが変わります。DOMContentLoaded や load、または次フレームで測定します。
window.addEventListener("load", () => {
const w = box.offsetWidth; // 安定した値
});
JavaScriptここが重要です:初回計測は“描画後”。連続測定は requestAnimationFrame でフレーム境界に合わせるとブレが減ります。
display: none は基本“測れない”
非表示(display:none)の要素は幅・高さが 0 になります。測る前に一時的に表示するか、測定用ラッパーで工夫します。
function measureShown(el, fn) {
const prev = el.style.display;
if (getComputedStyle(el).display === "none") el.style.display = "block";
const result = fn(el); // ここで offsetWidth などを読む
el.style.display = prev;
return result;
}
JavaScriptここが重要です:visibility:hidden ならスペースが残るため測定できます。アニメーション設計と合わせて切り替えを選びましょう。
実践例(アコーディオン、中央配置、同じ高さ揃え)
アコーディオン開閉:scrollHeight で“最大値”を取る
<button id="toggle">詳細</button>
<div id="panel" style="overflow:hidden; max-height:0; transition:max-height 200ms ease;">
<p>中身がたくさんある想定</p>
</div>
<script>
const panel = document.getElementById("panel");
document.getElementById("toggle").addEventListener("click", () => {
const open = panel.style.maxHeight && panel.style.maxHeight !== "0px";
panel.style.maxHeight = open ? "0px" : `${panel.scrollHeight}px`;
});
</script>
HTMLここが重要です:transition できない height の代わりに max-height を使い、scrollHeight を“ゴール値”にすると自然に開閉できます。
画面中央に要素を置く:rect で座標合わせ
<div id="modal" style="position:fixed; left:0; top:0;"></div>
<script>
const modal = document.getElementById("modal");
const { width, height } = modal.getBoundingClientRect();
modal.style.left = `calc(50% - ${width/2}px)`;
modal.style.top = `calc(50% - ${height/2}px)`;
</script>
HTMLここが重要です:transform: translate(-50%, -50%) の方が簡潔ですが、“確定サイズでドット単位に合わせたい”ときは rect を活用します。
カードの高さを揃える:最大 clientHeight を基準に
<div class="row">
<article class="card">短文</article>
<article class="card">とても長い説明が入るカード</article>
</div>
<script>
const cards = Array.from(document.querySelectorAll(".card"));
const max = Math.max(...cards.map(c => c.clientHeight));
cards.forEach(c => c.style.minHeight = `${max}px`);
</script>
HTMLここが重要です:flex や grid の機能でも揃えられますが、“内容に応じた最小高さ”を合わせたいときは clientHeight を使うと簡単です。
パフォーマンスの注意(レイアウトスラッシングを避ける)
幅・高さの取得は“レイアウト再計算”を誘発することがあります。直前に多数の style を変更してからすぐ offsetWidth を読むと、毎回レイアウトが走って重くなります。ここが重要です:読む(measure)→書く(mutate)の順を守り、複数要素はまとめて“先に全部読む→次に全部書く”。連続更新は requestAnimationFrame に乗せるとスムーズです。
まとめ
- 画面に見える箱の大きさは offset、内側の領域は client、中身の総サイズは scroll を使う。
- 座標系や精度が必要なら getBoundingClientRect。最終的な見え方は getComputedStyle。
- 計測は描画後。display:none の要素は測れないので一時表示や別手段をとる。
- 箱モデルと box-sizing を理解し、何を含めたいかで API を選ぶ。
- 読み書きの順序とフレーム境界を意識して、再計算負荷を抑える。
これらを押さえれば、初心者でも“欲しいサイズ”を正確に取り、レイアウトやアニメーションを意図通りにコントロールできます。
