【簡単】親要素にposition:relativeが付けられないときにJavaScriptで位置を制御する方法

※本ブログの目的は個人の備忘録であり、コードは参考用として掲載しています。
実際に使用される際は、ご自身の環境で十分に動作確認を行ってください。
コードの利用によって生じたいかなる問題についても責任を負いかねますので、あらかじめご了承ください。

Web制作やフロントエンド開発をしていると、「子要素を絶対配置したいのに、親要素に position: relative を付けられない」という状況に遭遇することがあります。

たとえば、対象としたい親要素にposition: relativeをつけるとレイアウトが崩れてしまう場合などが考えられます。

ですが、「どうしてもこの要素に合わせてこの要素を配置したい・・・!」なんてこともあるかと思います。

この記事では、そんな状況でも JavaScript を使って子要素の位置を正確に制御する方法 を解説します。

絶対配置の基本

CSS の position: absolute は、直近の position が relative, absolute, fixed, sticky の親要素 を基準に配置されます。

そのため、親に relative を付けられない場合、子要素は 想定外の位置に表示 されてしまいます。

レイアウトによって複雑な構造になってしまった場合、どうしても狙った要素にposition: relativeが付けられない場合もあるかと思います。

JavaScript で親要素に依存せず絶対配置する方法

親要素に relative を付けられない場合は、JSで親の位置を取得して、子要素に直接座標を設定 するのが解決策です。

const parent = document.querySelector('.js-parent');
const child = document.querySelector('.js-child');

const rect = parent.getBoundingClientRect();
child.style.position = 'absolute';
child.style.top = `${rect.top + window.scrollY}px`;
child.style.left = `${rect.left + window.scrollX}px`;

ポイント

getBoundingClientRect() とは

要素の ブラウザ表示領域(ビューポート)内での位置とサイズ を取得するメソッドです。

返されるオブジェクトには以下のような情報が含まれます。

{
  top: 要素の上端までの距離,
  left: 要素の左端までの距離,
  width: 要素の幅,
  height: 要素の高さ
}

つまり、画面上で 親要素がどの位置に描画されているか を数値で取得できます。

window.scrollY / window.scrollX とは

ページがどれだけスクロールされているかを表す値です。

  • window.scrollY: 縦方向のスクロール量(上から何pxスクロールしたか)
  • window.scrollX: 横方向のスクロール量

getBoundingClientRect() で得られる位置は スクロールを考慮していない(画面内での位置) ため、実際のドキュメント全体の位置に直すためには、スクロール量を足す必要があります。

つまり、rect.top は「画面の上からの距離」、window.scrollY は「スクロールされた量」です。

  • getBoundingClientRect() = ビューポートからの距離
  • window.scrollY = ビューポートまでの距離
  • 両者を足すとページ全体(ドキュメント)からの距離

それらを足すことで、「ページ全体の中での絶対位置」を求められます。

そうして絶対位置を求め、子要素のstyleに設定することで、親要素に relative を付けなくても子要素を正確に配置可能になります。

リサイズやスクロールにも対応する

固定座標だけだと、画面サイズが変わったときにズレてしまいます。
リサイズやスクロールに対応するには、イベントリスナーで位置を更新しましょう。

function updateChildPosition() {
  const rect = parent.getBoundingClientRect();
  child.style.top = `${rect.top + window.scrollY}px`;
  child.style.left = `${rect.left + window.scrollX}px`;
}

// 初期表示
updateChildPosition();

// ウィンドウのリサイズ・スクロール時に再計算
window.addEventListener('resize', updateChildPosition);
window.addEventListener('scroll', updateChildPosition);

これで、画面がリサイズされたりスクロールされても、子要素の位置が親要素に追従します。

まとめ

親要素に relative が付けられない場合でも、JavaScript を使えば以下のように柔軟に対応できます。

  1. 親要素の座標を取得する
  2. 子要素に position: absolute などの絶対配置のpositionを設定
  3. スクロールやリサイズに合わせて位置を更新

これにより、レイアウトやCMS、外部ライブラリで制約があっても、意図した通りの配置を実現できます。

完成コード

// 親・子要素を取得
const parent = document.querySelector('.js-parent');
const child = document.querySelector('.js-child');

// 子要素の位置を親に合わせて更新する関数
function updateChildPosition() {
  const rect = parent.getBoundingClientRect();
  child.style.position = 'absolute';
  child.style.top = `${rect.top + window.scrollY}px`;
  child.style.left = `${rect.left + window.scrollX}px`;
}

// 初期位置を設定
updateChildPosition();

// リサイズやスクロール時に位置を再計算
window.addEventListener('resize', updateChildPosition);
window.addEventListener('scroll', updateChildPosition);