要素の座標取得の基本 — el.getBoundingClientRect() と表示制御(classList.toggle('is-hidden'))
要素の「画面上での位置とサイズ」を取りたいときは getBoundingClientRect()。返ってくる DOMRect から、上(top)/左(left)/幅(width)/高さ(height)などがピクセルで分かります。取得した座標を使ってツールチップを配置したり、見える/見えないで表示を切り替えたりできます。
返り値とよく使うプロパティ
const rect = el.getBoundingClientRect();
console.log(rect.top, rect.left, rect.width, rect.height);
console.log(rect.right, rect.bottom); // 右端・下端
console.log(rect.x, rect.y); // left/top と同値(ブラウザ依存で同義)
JavaScript- 基準: ビューポート(画面の見えている領域)の左上が原点。スクロールすると値は変わります。
- 内容:
width/heightは border と padding を含む「見えている箱」のサイズ。 - 単位: ピクセル。小数になることもあります(拡大縮小やサブピクセル)。
例題1: ボタンの横にツールチップを正確に配置
<button id="info">情報</button>
<div id="tip" class="tip is-hidden">詳細ヘルプ</div>
<style>
.tip { position: fixed; background: #333; color: #fff; padding: 6px 8px; border-radius: 4px; }
.is-hidden { display: none; }
</style>
<script>
const btn = document.getElementById("info");
const tip = document.getElementById("tip");
btn.addEventListener("click", () => {
const r = btn.getBoundingClientRect(); // 画面上の位置とサイズ
tip.style.left = `${r.right + 8}px`; // ボタン右端から8px右
tip.style.top = `${r.top}px`; // ボタンの上端に揃える
tip.classList.toggle("is-hidden"); // 表示/非表示を切り替え
});
// スクロール時も位置が画面基準で合うよう、position: fixed を採用
</script>
HTML- ポイント:
position: fixedを使うと、rectの値(画面基準)と座標指定が一致して楽です。 - 補足:
position: absoluteを使う場合は、ページスクロール量window.scrollX/scrollYを加算して調整します。
例題2: 画面内に見えているかで表示を切り替え
<div id="panel" class="panel is-hidden">コンテンツ</div>
<button id="toggle">見えるときだけ表示</button>
<style>
.panel { position: fixed; right: 16px; bottom: 16px; background: #eee; padding: 8px; }
.is-hidden { display: none; }
</style>
<script>
const panel = document.getElementById("panel");
const btn = document.getElementById("toggle");
function inViewport(el) {
const r = el.getBoundingClientRect();
const vw = window.innerWidth;
const vh = window.innerHeight;
return r.bottom > 0 && r.top < vh && r.right > 0 && r.left < vw;
}
btn.addEventListener("click", () => {
const visible = inViewport(btn);
panel.classList.toggle("is-hidden", !visible); // ボタンが画面内なら表示
});
window.addEventListener("resize", () => {
const visible = inViewport(btn);
panel.classList.toggle("is-hidden", !visible);
});
</script>
HTML- ポイント: 矩形がビューポートと重なっているかで判定。
resize/scrollに応じて更新します。 - 応用: 特定エリアに入ったらヘッダーを出す、下に来たら「トップへ戻る」ボタンを出すなど。
例題3: 絶対配置でツールチップ(スクロール補正あり)
<button id="save" style="margin-top: 1000px;">保存</button>
<div id="tip" class="tip is-hidden">保存の説明</div>
<style>
.tip { position: absolute; background: #333; color: #fff; padding: 6px 8px; }
.is-hidden { display: none; }
</style>
<script>
const btn = document.getElementById("save");
const tip = document.getElementById("tip");
btn.addEventListener("click", () => {
const r = btn.getBoundingClientRect();
const x = r.right + 8 + window.scrollX; // ページ座標に変換
const y = r.top + window.scrollY;
tip.style.left = `${x}px`;
tip.style.top = `${y}px`;
tip.classList.toggle("is-hidden");
});
</script>
HTML- ポイント: 画面基準の
rectに、ページスクロール量を加えると「ページ座標」で配置できます。 - 使い分け: fixed(楽・スクロール追従) vs absolute(ページ座標に合わせたいとき)。
実務でのコツとハマりやすい点
- 計算タイミング:
- ラベル: CSSのアニメーションやトランスフォーム中は値が動く。必要なフレームで計算するか
requestAnimationFrameを使う。
- ラベル: CSSのアニメーションやトランスフォーム中は値が動く。必要なフレームで計算するか
- スケール/ズーム:
- ラベル: 拡大縮小(
transform: scale)やブラウザズームで小数値になる。四捨五入は目的に応じて。
- ラベル: 拡大縮小(
- 境界衝突の処理:
- ラベル: 右端でハミ出す場合は
Math.min(r.right + 8, window.innerWidth - tip.offsetWidth - 8)のようにクリップ。
- ラベル: 右端でハミ出す場合は
- 再レイアウト:
- ラベル:
getBoundingClientRect()はレイアウト計算を引き起こすことがある。大量呼び出しはまとめて、不要な再計算を避ける。
- ラベル:
練習問題(配置と表示の組み合わせを体験)
<button id="btn">ヘルプ</button>
<div id="help" class="bubble is-hidden">ここに説明が出ます</div>
<style>
.bubble { position: fixed; background: #222; color: #fff; padding: 8px 10px; border-radius: 6px; }
.is-hidden { display: none; }
</style>
<script>
const btn = document.getElementById("btn");
const help = document.getElementById("help");
function placeBubble(anchor, bubble) {
const r = anchor.getBoundingClientRect();
bubble.style.left = `${r.left}px`;
bubble.style.top = `${r.bottom + 8}px`; // アンカーの下に 8px
}
btn.addEventListener("click", () => {
placeBubble(btn, help);
help.classList.toggle("is-hidden");
});
window.addEventListener("resize", () => {
if (!help.classList.contains("is-hidden")) placeBubble(btn, help);
});
</script>
HTML- 課題: 画面幅が狭いときは気持ち右寄せにする、などのクリップ処理を追加してみてください。
直感的な指針
- 位置は
getBoundingClientRect()、見せる/隠すはclassList.toggle('is-hidden')。 - fixed ならそのまま座標指定、absolute なら
scrollX/scrollYを加算。 - ビューポートと境界の関係を意識して、クリップ・再計算のタイミングを整える。
