JavaScriptで要素の位置座標を簡単に取得する7つの方法

JavaScriptで要素の位置座標を取得する7つの方法JS
この記事は約23分で読めます。

※本記事のコンテンツは、利用目的を問わずご活用いただけます。実務経験10000時間以上のエンジニアが監修しており、常に解説内容のわかりやすさや記事の品質に注力しておりますので、不具合・分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。(理解できない部分などの個別相談も無償で承っております)
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●JavaScriptで座標取得が必要な理由

今回は、JavaScriptで要素の座標を取得する方法について詳しく解説していきます。

でも、そもそもなぜ座標の取得が必要なのでしょうか?

実は、現代のWebアプリケーションやWebサイトを作る上で、座標の取得は非常に重要な役割を果たしているんです。

○Webアプリケーションでの重要性

JavaScriptで座標を取得することは、インタラクティブなWebアプリケーションを開発する上で欠かせません。

ユーザーのマウス操作やタッチ操作に応じて、要素を動かしたり、アニメーションを起こしたりするには、その要素がどこに位置しているかを正確に把握する必要があります。

座標取得なくしては、ドラッグ&ドロップ機能や、スクロールに連動した要素の動きなど、ユーザーエクスペリエンスを高める様々な機能の実装が困難になってしまうのです。

○アニメーションやインタラクションへの応用

JavaScriptによる座標取得は、Webサイトをよりダイナミックで魅力的なものにするためにも重要です。

例えば、マウスの動きに合わせて画像が拡大したり、視差効果でコンテンツが動いたりするような、洗練されたアニメーションを実装するには、要素の位置を随時取得し、それに基づいて要素のスタイルを変更する必要があります。

また、クリックやタップされた位置に応じて、適切な処理を行うインタラクティブな機能を実装する際にも、座標取得は不可欠なのです。

では、指定された目次の部分について、SEOに最適化された文章で解説していきましょう。

●座標取得の基本 – getBoundingClientRect()

JavaScriptで要素の座標を取得するための基本中の基本が、getBoundingClientRect()メソッドです。

このメソッドは、要素の位置とサイズに関する情報を含むDOMRectオブジェクトを返してくれます。

getBoundingClientRect()は、ほとんどのモダンブラウザでサポートされているので、安心して使うことができますよ。

○getBoundingClientRect()の使い方

getBoundingClientRect()の使い方は、とてもシンプルです。

座標を取得したい要素に対して、このメソッドを呼び出すだけ。

例えば、idがexampleの要素の座標を取得したい場合は、こんな感じでコードを書きます。

const element = document.getElementById('example');
const rect = element.getBoundingClientRect();

これだけで、rectオブジェクトに要素の座標とサイズが格納されるんです。

簡単ですね。

○サンプルコード1:要素の位置とサイズを取得

実際に、getBoundingClientRect()を使って要素の位置とサイズを取得してみましょう。

次のようなHTMLがあるとします。

<div id="example" style="width: 200px; height: 100px; margin: 50px;">
  Example Element
</div>

このexample要素の座標とサイズを、getBoundingClientRect()を使って取得するコードは、こんな感じになります。

const element = document.getElementById('example');
const rect = element.getBoundingClientRect();

console.log(`要素の位置: (${rect.left}, ${rect.top})`);
console.log(`要素のサイズ: ${rect.width} x ${rect.height}`);

このコードを実行すると、コンソールにはこのような結果が表示されます。

要素の位置: (50, 50)
要素のサイズ: 200 x 100

rectオブジェクトのleft、top、width、heightプロパティを使えば、要素の位置とサイズを簡単に取得できるのがわかりますね。

getBoundingClientRect()は、要素の座標を取得するための強力な味方ですが、もっと詳細に座標を取得したいこともあるでしょう。

そんなときに頼りになるのが、getClientRects()メソッドなんです。

●より詳細に – getClientRects()

getClientRects()は、getBoundingClientRect()よりも詳細な座標情報を提供してくれるメソッドです。

なぜ、より詳細な座標が必要になるかというと、インライン要素のように、複数の矩形領域を持つ要素の座標を取得する場合などがあるからです。

getBoundingClientRect()では、要素全体を囲む1つの矩形しか取得できませんが、getClientRects()を使えば、要素内の各矩形の座標を個別に取得することができるんです。

○getClientRects()の特徴

getClientRects()は、要素内の各行や各インライン要素に対応する矩形の情報を含むDOMRectListオブジェクトを返します。

DOMRectListオブジェクトは、矩形の数だけDOMRectオブジェクトを含む配列のようなオブジェクトです。

各DOMRectオブジェクトには、getBoundingClientRect()と同様に、left、top、right、bottom、width、heightプロパティが含まれています。

では、実際にgetClientRects()を使ってみましょう。

○サンプルコード2:インライン要素の座標を取得

次のようなHTMLがあるとします。

<p>
  This is an <span>inline</span> element with <span>multiple</span> lines.
</p>

この例では、p要素内に2つのspan要素があり、それぞれ別の行に配置されています。

getClientRects()を使って、これらのspan要素の座標を取得してみましょう。

const inlineElements = document.querySelectorAll('p span');

inlineElements.forEach((element, index) => {
  const rects = element.getClientRects();

  console.log(`span要素${index + 1}の矩形数: ${rects.length}`);

  rects.forEach((rect, rectIndex) => {
    console.log(`  矩形${rectIndex + 1}の座標: (${rect.left}, ${rect.top})`);
    console.log(`  矩形${rectIndex + 1}のサイズ: ${rect.width} x ${rect.height}`);
  });
});

このコードを実行すると、コンソールには次のような結果が表示されます。

span要素1の矩形数: 1
  矩形1の座標: (22, 19)
  矩形1のサイズ: 33 x 19
span要素2の矩形数: 1
  矩形1の座標: (22, 38)
  矩形1のサイズ: 49 x 19

こんな形で、getClientRects()を使えば、インライン要素など、複数の矩形領域を持つ要素の座標を詳細に取得することができます。

これは、より高度なUIを実装する際に役立つテクニックなので、ぜひ覚えておいてくださいね。

●ビューポートとの関係 – clientLeft, clientTop

要素の座標を正確に理解するためには、ビューポートとの関係を知っておく必要があります。

etBoundingClientRect()やgetClientRects()で取得した座標は、ビューポートを基準とした相対的な位置を表しています。

しかし、要素の境界線(ボーダー)の幅によっては、座標が少しずれることがあるんです。

そのズレを計算するのに役立つのが、clientLeftとclientTopプロパティなんですね。

○clientLeft, clientTopの意味

clientLeftとclientTopは、要素のボーダーの幅を表すプロパティです。

より具体的には次のような意味を持っています。

clientLeft:要素の左側のボーダーの幅(ピクセル単位)
clientTop:要素の上側のボーダーの幅(ピクセル単位)

ただし、これらのプロパティは、ボーダーがない場合や、ボーダーの幅が0の場合は、常に0を返します。

では、実際にclientLeftとclientTopを使って、要素のビューポート内での正確な位置を計算してみましょう。

○サンプルコード3:ビューポート内での位置を計算

次のようなHTMLがあるとします。

<div id="example" style="position: absolute; left: 100px; top: 200px; border: 5px solid black;">
  Example Element
</div>

この例では、divがabsolute positioningを使って、ビューポートの左上から(100px, 200px)の位置に配置されています。

また、黒色の5pxの幅のボーダーが設定されています。

ここで、getBoundingClientRect()を使ってdivの位置を取得し、clientLeftとclientTopを考慮して、ビューポート内での正確な位置を計算してみます。

const element = document.getElementById('example');
const rect = element.getBoundingClientRect();

const viewportLeft = rect.left + element.clientLeft;
const viewportTop = rect.top + element.clientTop;

console.log(`ビューポート内での位置: (${viewportLeft}, ${viewportTop})`);

このコードを実行すると、コンソールには次のような結果が表示されます。

ビューポート内での位置: (105, 205)

clientLeftとclientTopを使えば、要素のボーダーの幅を考慮して、ビューポート内での正確な位置を計算することができます。

特にボーダーの幅が大きい要素を扱う場合には、これらのプロパティを活用することで、より正確な座標計算が可能になるでしょう。

●スクロール量を考慮 – pageXOffset, pageYOffset

ビューポートを基準とした座標は、ページがスクロールされた状態では、要素の実際の位置とは異なります。

なぜなら、スクロールによってビューポートの位置がずれるからです。

そこで、スクロール量を考慮して、要素の絶対的な位置を計算する必要が出てくるんです。

○スクロール量の取得方法

スクロール量を取得するには、window.pageXOffsetとwindow.pageYOffsetを使います。

これらのプロパティは、それぞれ水平方向と垂直方向のスクロール量をピクセル単位で返してくれます。

ただし、これらのプロパティはIE8以下では対応していないので注意が必要です。

IE8以下でも対応するには、document.documentElement.scrollLeftとdocument.documentElement.scrollTopを使う必要があります。

では、実際にスクロール量を考慮した座標の取得方法を見ていきましょう。

○サンプルコード4:スクロール位置を加味した座標

次のようなHTMLがあるとします。

<div id="example" style="position: absolute; left: 100px; top: 1000px;">
  Example Element
</div>

この例では、div要素がページの上から1000pxの位置に配置されています。

スクロールしないと画面内に表示されない位置ですね。

ここで、getBoundingClientRect()とpageXOffset/pageYOffsetを使って、スクロール量を考慮したdiv要素の絶対的な位置を計算してみましょう。

const element = document.getElementById('example');
const rect = element.getBoundingClientRect();

const scrollX = window.pageXOffset || document.documentElement.scrollLeft;
const scrollY = window.pageYOffset || document.documentElement.scrollTop;

const absoluteLeft = rect.left + scrollX;
const absoluteTop = rect.top + scrollY;

console.log(`要素の絶対的な位置: (${absoluteLeft}, ${absoluteTop})`);

このコードを実行し、ページを500pxスクロールした状態だとします。

すると、コンソールには次のような結果が表示されます。

要素の絶対的な位置: (100, 1500)

pageXOffset/pageYOffsetを使えば、スクロール量を考慮した要素の絶対的な位置を計算することができます。

これは、スクロールが発生するようなWebページで要素の座標を取得する際に、とても重要なテクニックとなります。

ぜひ、スクロール量の取得方法を覚えておいてくださいね。

●より汎用的に – elementFromPoint()

elementFromPoint()は、指定した座標に存在する要素を返してくれるメソッドです。

これを使えば、特定の座標にどの要素が配置されているのかを簡単に知ることができます。

マウスクリックやタッチイベントなどで、ユーザーがどの要素を操作したのかを判定する際に、とても便利なメソッドなんです。

○elementFromPoint()の使い方

elementFromPoint()の使い方は、とてもシンプルです。

window.document.elementFromPoint(x, y)のように、x座標とy座標を引数に渡すだけ。

返り値は、指定した座標に存在する最上位の要素になります。

ただし、elementFromPoint()は、座標がビューポートの外にある場合や、座標上に要素が存在しない場合は、nullを返すので注意が必要ですね。

では、実際にelementFromPoint()を使ってみましょう。

○サンプルコード5:指定座標の要素を取得

次のようなHTMLがあるとします。

<div id="parent" style="position: relative; width: 500px; height: 500px;">
  <div id="child1" style="position: absolute; left: 100px; top: 100px; width: 200px; height: 200px; background-color: red;"></div>
  <div id="child2" style="position: absolute; left: 200px; top: 200px; width: 200px; height: 200px; background-color: blue;"></div>
</div>

この例では、parent要素内に2つの子要素(child1とchild2)があり、それぞれ絶対位置で配置されています。

ここで、(150, 150)の座標にある要素を取得してみましょう。

const element = document.elementFromPoint(150, 150);

console.log(element.id); // "child1"

このコードを実行すると、コンソールには”child1″が表示されます。

(150, 150)の座標は、child1要素の範囲内にあるからですね。

elementFromPoint()を使えば、指定した座標にある要素を簡単に取得することができます。

これは、ユーザーのマウス操作やタッチ操作に応じて、適切な処理を行うようなインタラクティブなWebサイトを開発する際に、とても重宝するメソッドです。

ぜひ、覚えておいてくださいね。

●イベントオブジェクトを活用 – event.clientX, event.clientY

マウスクリックやタッチイベントが発生したときの座標を知るには、イベントオブジェクトのプロパティを活用するのが最も簡単で確実な方法です。

イベントオブジェクトには、event.clientXとevent.clientYというプロパティがあり、これらがクリックやタッチの座標を表しているんです。

○イベントオブジェクトから座標を取得

event.clientXとevent.clientYの使い方は、とてもシンプルです。

マウスイベントやタッチイベントのリスナー関数の引数として渡されるイベントオブジェクトから、これらのプロパティにアクセスするだけ。

  • event.clientX:クリックやタッチのビューポート上のX座標
  • event.clientY:クリックやタッチのビューポート上のY座標

ただし、これらの座標はビューポートを基準としているので、スクロール位置は考慮されていません。

スクロール位置を加味した座標が必要な場合は、pageXOffset/pageYOffsetを足し合わせる必要があります。

では、実際にイベントオブジェクトから座標を取得してみましょう。

○サンプルコード6:クリック位置の座標を取得

次のようなHTMLがあるとします。

<div id="example" style="width: 400px; height: 400px; background-color: lightblue;"></div>

この要素をクリックしたときの座標を取得するコードは、こんな感じになります。

const element = document.getElementById('example');

element.addEventListener('click', (event) => {
  const clickX = event.clientX;
  const clickY = event.clientY;

  console.log(`クリック位置: (${clickX}, ${clickY})`);
});

このコードを実行して、要素の左上付近をクリックすると、コンソールには次のような結果が表示されます。

クリック位置: (42, 35)

イベントオブジェクトのclientXとclientYを使えば、マウスクリックやタッチイベントの座標を簡単に取得できます。

これは、ユーザーのインタラクションに応じた処理を実装する際に、非常に重宝するテクニックです。

ぜひ、イベントオブジェクトを活用して、よりインタラクティブなWebサイトを開発してみてくださいね。

●jQuery版 – offset(), position()

jQueryを使っている方もいると思うので、jQueryでの座標取得方法も見ていきましょう。

jQueryには、要素の位置を取得するためのメソッドとして、offset()とposition()があります。

○jQueryでの座標取得

offset()とposition()は、どちらも要素の位置を取得するメソッドですが、座標の基準が異なります。

  • offset():ドキュメントを基準とした要素の位置を取得
  • position():親要素を基準とした要素の位置を取得

offset()は、getBoundingClientRect()とpageXOffset/pageYOffsetを組み合わせたような結果を返し、position()は、getClientRects()に近い結果を返します。

では、実際にjQueryで要素の位置を取得してみましょう。

○サンプルコード7:jQueryで要素の位置を取得

次のようなHTMLがあるとします。

<div id="parent" style="position: relative; width: 400px; height: 400px; margin: 50px; border: 10px solid black;">
  <div id="child" style="position: absolute; left: 100px; top: 100px; width: 200px; height: 200px; background-color: lightblue;"></div>
</div>

この例では、child要素がparent要素内で絶対位置指定されています。

offset()とposition()を使って、child要素の位置を取得してみます。

const child = $('#child');

const offsetPosition = child.offset();
const relativePosition = child.position();

console.log(`offset: (${offsetPosition.left}, ${offsetPosition.top})`);
console.log(`position: (${relativePosition.left}, ${relativePosition.top})`);

このコードを実行すると、コンソールには次のような結果が表示されます。

offset: (160, 160)
position: (100, 100)

offset()の結果は、ドキュメントを基準とした位置なので、parent要素のマージンとボーダーが加算されています。

一方、position()の結果は、parent要素を基準とした位置なので、child要素のleftとtopの値そのものになっています。

●よくあるエラーと対処法

JavaScriptで座標取得を行う際、次のようなエラーに遭遇することがあります。

○座標が思った位置と違う場合

座標がずれる原因としては、次のようなことが考えられます。

  • ボーダーやパディングを考慮していない
  • スクロール量を加味していない
  • 親要素の位置を考慮していない

これらの問題を解決するには、次のような対処法があります。

  • ボーダーやパディングを考慮する場合は、clientLeftとclientTopを使う
  • スクロール量を加味する場合は、pageXOffset/pageYOffsetを使う
  • 親要素の位置を考慮する場合は、offsetParent要素からの相対位置を計算する

座標がずれる原因を正しく理解し、適切な対処法を知っておければ、思った通りの位置を取得できるはずです。

○座標取得時のレイアウトシフト問題

JavaScriptで要素の座標を取得する際、レイアウトシフトが発生することがあります。

レイアウトシフトとは、要素の位置や大きさが変化することで、座標取得の結果に影響を与えてしまう現象です。

レイアウトシフトを防ぐには、次のような対処法があります。

  • 座標取得前に、要素のサイズを固定する
  • 座標取得前に、要素を非表示にしておき、取得後に再び表示する
  • 座標取得の直前に、getBoundingClientRect()などを呼び出して、強制的にリフローを発生させる

レイアウトシフトが発生しないよう、適切な対処法を講じることが大切です。

○座標取得のタイミングとイベントループ

JavaScriptは、シングルスレッドで動作するイベントループベースの言語です。

そのため、座標取得のタイミングによっては、思わぬ結果になることがあります。

座標取得のタイミングに注意するためには、次のようなことを心がけましょう。

  • DOMの更新後に座標を取得する
  • 非同期処理の完了を待ってから座標を取得する
  • requestAnimationFrame()を使って、適切なタイミングで座標を取得する

イベントループを理解し、適切なタイミングで座標を取得することが重要です。

エラーに遭遇しても、あきらめないでくださいね。原因を突き止め、適切な対処法を見つけることが、JavaScriptマスターへの近道です。

●座標取得の応用例

ここまで、JavaScriptで要素の座標を取得する様々な方法を解説してきました。

最後に、座標取得を応用した実践的なテクニックを見ていきましょう。

○サンプルコード8:要素の中心位置を計算

要素の中心位置を計算することで、より洗練されたアニメーションやインタラクションを実装できます。

getBoundingClientRect()を使って、要素の中心位置を計算するコードは、こんな感じです。

function getElementCenter(element) {
  const rect = element.getBoundingClientRect();
  return {
    x: rect.left + rect.width / 2,
    y: rect.top + rect.height / 2
  };
}

const element = document.getElementById('example');
const center = getElementCenter(element);
console.log(`要素の中心位置: (${center.x}, ${center.y})`);

要素の中心位置を計算することで、より精緻なUIを実現できます。

○サンプルコード9:要素同士の重なり判定

要素同士の重なり判定は、ゲームやインタラクティブなアプリケーションでよく使われるテクニックです。

getBoundingClientRect()を使って、2つの要素が重なっているかどうかを判定するコードは、こんな感じです。

function isOverlapping(element1, element2) {
  const rect1 = element1.getBoundingClientRect();
  const rect2 = element2.getBoundingClientRect();

  return !(
    rect1.right < rect2.left ||
    rect1.left > rect2.right ||
    rect1.bottom < rect2.top ||
    rect1.top > rect2.bottom
  );
}

const element1 = document.getElementById('example1');
const element2 = document.getElementById('example2');
console.log(`要素が重なっているか: ${isOverlapping(element1, element2)}`);

要素同士の重なり判定は、ゲームなどのインタラクティブなアプリケーションを開発する上で重要です。

○サンプルコード10:マウス追従アニメーション

マウスの動きに合わせて要素を動かすアニメーションは、Webサイトをよりインタラクティブで魅力的なものにしてくれます。

マウスの位置を取得し、要素の位置をマウスに追従させるコードは、こんな感じです。

const element = document.getElementById('example');

document.addEventListener('mousemove', (event) => {
  const mouseX = event.clientX;
  const mouseY = event.clientY;

  element.style.left = `${mouseX}px`;
  element.style.top = `${mouseY}px`;
});

このコードを実行すると、id=”example”の要素が、マウスの動きに合わせて移動するようになります。

まとめ

JavaScriptで要素の座標を取得することは、Webアプリケーションやインタラクティブなサイトを開発する上で欠かせないスキルです。

getBoundingClientRect()やgetClientRects()、elementFromPoint()など、様々なメソッドを使い分けることで、シーンに応じた最適な座標取得が可能になります。

JavaScriptの座標取得は、初心者にとってハードルが高く感じるかもしれません。

でも、基本的なメソッドをマスターし、実践的なテクニックを身につければ、きっとあなたも魅力的なWebサイトやアプリケーションを開発できるようになります。

この記事で学んだことを活かして、ぜひJavaScriptの座標取得をマスターしてください。