getBoundingClientRect とは何か
getBoundingClientRect は、要素の「画面(ビューポート)に対する位置とサイズ」を返すメソッドです。返ってくる値は小数を含む CSS ピクセルで、スクロールやズーム、CSS 変形(transform)の影響が反映されます。ここが重要です:ページ内の相対座標(offsetTop/Left)ではなく“今見えている画面”基準の座標を得られるため、ポップアップの位置合わせ、可視判定、交差判定など“画面目線”の処理に最適です。
返されるプロパティ(意味と使いどころ)
基本プロパティの意味
- left/top: 画面左上から見た要素の左端・上端の位置(負になることもある)
- right/bottom: 要素の右端・下端の位置(ビューポート基準)
- width/height: 要素の見た目の幅・高さ(padding と border を含む。margin は含まない)
- x/y: left/top と同義のショートハンド
ここが重要です:値は小数(サブピクセル)になり得ます。精密な重なり判定や線形補間が必要な処理では、この“小数の正確さ”が効きます。
スクロール・ズーム・変形の影響
- スクロール: rect は常に画面基準。スクロールすると値が変わります。
- ズーム: 値は CSS ピクセルで返るため、見え方に準じて変化します。
- transform: scale/translate などの変形は rect に反映されます(変形後の見た目の箱)。
ここが重要です:見え方に合わせた UI(ツールチップ位置、当たり判定)をしたいなら rect が唯一の正解です。
基本の使い方(画面座標の取得とページ座標への変換)
画面座標を読む
<div id="box" style="width:160px; height:80px; border:1px solid #333">内容</div>
<script>
const r = box.getBoundingClientRect();
console.log(r.left, r.top, r.width, r.height);
}
</script>
HTMLここが重要です:getBoundingClientRect() は“いまの画面に対して”の位置とサイズ。スクロールやズームを意識せず、常に正しい画面座標が取れます。
ページ左上からの絶対座標に変換する
<script>
const r = box.getBoundingClientRect();
const pageLeft = window.scrollX + r.left;
const pageTop = window.scrollY + r.top;
</script>
HTMLここが重要です:ページ基準の絶対座標が必要なら、rect に現在のスクロール量(scrollX/scrollY)を足し込みます。固定ヘッダの補正などもこの組み合わせで行います。
代表的なユースケース(ポップアップ、可視判定、当たり判定)
要素に対してツールチップを正確に配置
<div id="btn">ボタン</div>
<div id="tip" style="position:fixed; display:none">ヒント</div>
<script>
function showTip(anchor, tip) {
const r = anchor.getBoundingClientRect();
tip.style.left = (r.left + r.width / 2) + "px";
tip.style.top = (r.bottom + 8) + "px"; // 8px 下に出す
tip.style.display = "block";
}
showTip(btn, tip);
</script>
HTMLここが重要です:position: fixed と rect のペアは、画面基準の位置合わせに強い組み合わせです。スクロールしても位置が崩れません。
画面内に見えているかを判定(マージン付き)
<script>
function isInViewport(el, margin = 0) {
const r = el.getBoundingClientRect();
return r.bottom > -margin && r.top < window.innerHeight + margin &&
r.right > -margin && r.left < window.innerWidth + margin;
}
console.log("見えている?", isInViewport(document.getElementById("box"), 50));
</script>
HTMLここが重要です:可視判定は rect と画面サイズ(innerWidth/innerHeight)で十分です。margin を持たせると“近づいたら先にロード”のような先読みができます。
当たり判定(要素どうしの交差)
<script>
function intersects(a, b) {
const ra = a.getBoundingClientRect();
const rb = b.getBoundingClientRect();
return !(ra.right < rb.left || ra.left > rb.right || ra.bottom < rb.top || ra.top > rb.bottom);
}
</script>
HTMLここが重要です:2つの矩形が重なっているかは、四辺の比較で判定できます。ドラッグ&ドロップやハイライトに応用できます。
offset/client と rect の使い分け(基準の違い)
それぞれの基準
- offsetLeft/Top: offsetParent(レイアウト上の基準の親)に対する相対位置。外側寸法は offsetWidth/Height(整数)。
- clientWidth/Height: 内側領域(content+padding)。スクロールバー・border なし(整数)。
- boundingClientRect: 画面に対する位置とサイズ。スクロール・ズーム・transform 反映(小数)。
ここが重要です:親内のレイアウト計算やドラッグ基準なら offset、内側レイアウトなら client、画面目線の位置合わせ・可視判定なら rect。目的に合わせて基準を選ぶと計算がシンプルになり、ズレが消えます。
スクロールと固定ヘッダの“隠れない”補正
固定ヘッダで隠れない位置にスクロール
<header style="position:sticky; top:0; height:64px"></header>
<section id="target" style="margin-top:1000px">目的地</section>
<script>
function scrollToVisibleTop(el, header = 0) {
const r = el.getBoundingClientRect();
const y = window.scrollY + r.top - header;
window.scrollTo({ top: Math.max(y, 0), behavior: "smooth" });
}
scrollToVisibleTop(target, 64);
</script>
HTMLここが重要です:rect.top は画面基準の位置。スクロール量を足し、ヘッダ高さを引けば、ちょうど見える位置に止まります。
パフォーマンスと注意点(計測→更新の順序、非表示、インライン)
レイアウトスラッシングを避ける
- 計測と更新の分離:
ポイント: まず getBoundingClientRect で“読む”(計測)→ 次のフレームで“書く”(スタイル更新)。requestAnimationFrame を使うと安全。 - まとめて計測:
複数要素の rect が必要なら、1フレーム内でまとめて読み、その後まとめて更新する。
ここが重要です:計測と更新を交互に混ぜると再レイアウトが多発し、カクつきます。順序を分けるのがコツです。
display: none の要素は 0 を返す
非表示(display: none)はレイアウト計算されないため、rect は 0 になります。事前計測したい場合は visibility: hidden(見えないがレイアウト参加)にして測りましょう。ここが重要です:“見え方の箱”という定義に沿った計測が必要です。
インライン要素が折り返す場合
getBoundingClientRect は“全体の外接矩形”を返します。行をまたぐテキストなど“各行の矩形”が欲しいなら getClientRects() を使います。ここが重要です:外接矩形では上下に余分が入ることがあるため、用途に応じて API を選びます。
まとめ
getBoundingClientRect は、要素の「画面(ビューポート)に対する正確な位置とサイズ」を小数で返すメソッドです。スクロール・ズーム・transform を反映し、ポップアップの配置、可視判定、交差判定、固定ヘッダ補正付きスクロールなど“画面目線”の処理に不可欠です。offset/client と基準が違うため、目的に応じた使い分けを徹底すると計算が短く、ズレのない UI が作れます。計測と更新の順序を分け、非表示やインラインの特性に注意すれば、初心者でも直感的に扱える堅実な実装ができます。
