JavaScript | DOM 操作:CSS / クラス操作 – 要素の高さ・幅の取得

JavaScript
スポンサーリンク

要素の高さ・幅の「どれを測るか」

同じ「幅・高さ」でも、境界や余白の扱いで数値が変わります。どの 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 を選ぶ。
  • 読み書きの順序とフレーム境界を意識して、再計算負荷を抑える。

これらを押さえれば、初心者でも“欲しいサイズ”を正確に取り、レイアウトやアニメーションを意図通りにコントロールできます。

タイトルとURLをコピーしました