ドキュメントに対する要素の位置を見つける


113

ドキュメント/ボディ/ブラウザウィンドウに対する要素の位置を決定する最も簡単な方法は何ですか?

現在、私はを使用.offsetLeft/offsetTopしていますが、このメソッドは親要素に対する相対的な位置のみを提供するため、body /ブラウザウィンドウ/ドキュメントの位置に対する相対的な位置を知るには、body要素に対する親の数を決定する必要があります。

この方法も面倒です。

回答:


60

offsetParentDOMの最上位までトラバースできます。

function getOffsetLeft( elem )
{
    var offsetLeft = 0;
    do {
      if ( !isNaN( elem.offsetLeft ) )
      {
          offsetLeft += elem.offsetLeft;
      }
    } while( elem = elem.offsetParent );
    return offsetLeft;
}

28
いいえ、親(特にhtml要素!!!)にマージン、パディング、またはボーダーがある場合は、そうではありません。
Flash Thunder

余白について... box-sizingをborder-box ...またはそれらの線に沿って何かを設定すると役立つかもしれません...修正できないものは何もありません...

最初に、ボックスサイズに従って境界とマージンを考慮するかどうかを決定する必要があります。第二に、崩壊したマージンを考慮する必要があります。そして最後に、この回答をさらに悪化させる、より複雑な状況が将来発生するでしょう。
xianshenglu

5
なぜこれが受け入れられた答えなのですか?これは古く、パフォーマンスが低いです。他の回答で提案されているように、自分でお願いし、getBoundingClientRect()を使用してください。
Fabian von Ellerts、

175

次のようにDOMをトラバースすることなく、トップレフトを取得できます。

function getCoords(elem) { // crossbrowser version
    var box = elem.getBoundingClientRect();

    var body = document.body;
    var docEl = document.documentElement;

    var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
    var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;

    var clientTop = docEl.clientTop || body.clientTop || 0;
    var clientLeft = docEl.clientLeft || body.clientLeft || 0;

    var top  = box.top +  scrollTop - clientTop;
    var left = box.left + scrollLeft - clientLeft;

    return { top: Math.round(top), left: Math.round(left) };
}

6
この回答では、親のオフセットは考慮されていません。ビューポートとの相対的な関係のみ
ニッキー

3
@Nickeyは正しくありません。ビューポートの位置とスクロールオフセットのチェックにより、ドキュメント全体を基準とした座標が得られます。
natchiketa 2016

1
モバイルデバイスでバグが発生する可能性があるstackoverflow.com/a/32623832/962634調査が必要
バジル

1
clientTop / clientLeftを差し引くのはなぜですか?
Teemoh 2017年

1
@Teemoh clientTop / clientLeftは、<html>要素の境界線の値に対応します。
Raphael Rafatpanah

98

を使用element.getBoundingClientRect()して、ビューポートに対する要素の位置を取得できます。

次に、を使用document.documentElement.scrollTopしてビューポートのオフセットを計算します。

2つの合計は、ドキュメントに対する要素の位置を示します。

element.getBoundingClientRect().top + document.documentElement.scrollTop

10
ビューポートに対する相対は、ドキュメントに対する相対と同じではありません。ページが少し下にスクロールされると、ビューポートに相対的な上部は、ドキュメントに相対的な上部よりも小さい数値になります。
MrVimes 2014年

14
彼はビューポートを基準に開始し、ドキュメントを基準にしてそれを取得するためにscrollYを追加します。
ホアキンクエンカアベラ2017年

2
document.documentElement.scrollTopSafariでは機能しません。window.scrollY代わりに使用してください
Fabian von Ellerts

7

私は使用をお勧めします

element.getBoundingClientRect()

ここで提案されている ように、offsetLeftoffsetTop、およびoffsetParentによる手動のオフセット計算の代わりに。ここ で提案されているとおり状況によっては*手動トラバーサルは無効な結果を生成します。このPlunkerを参照してください:http ://plnkr.co/pC8Kgj

*要素が静的(=デフォルト)の位置にあるスクロール可能な親の内部にある場合。


scrollLeftとscrollTopを組み込むことによっても、オフセット計算を機能させることができます。
Ben J

しかし、私が見つかりました。offsetLeftそしてoffsetTop、アカウントCSS3の変換、に取ることはありませんgetBoundingClientRect()ありません。そのため、結果が無効になる場合があります。必要な場合は、を使用して、要素の親に対するオフセット(などoffsetLeft)を取得できます(element.getBoundingClientRect().left - parent.getBoundingClientRect().left)
ベンJ

defは高くなるはずです。これらの値ははるかに有用であり、すべて1回の呼び出しでも実行できます。
mix3d、2018年

7

document-offsetサードパーティのスクリプト)は興味深いものであり、ここで他の回答からのアプローチを活用しているようです。

例:

var offset = require('document-offset')
var target = document.getElementById('target')
console.log(offset(target))
// => {top: 69, left: 108} 

5

次のメソッドは、offsetTop / offsetLeftをトリップするエッジケースを処理するときに最も信頼できることがわかりました。

function getPosition(element) {
    var clientRect = element.getBoundingClientRect();
    return {left: clientRect.left + document.body.scrollLeft,
            top: clientRect.top + document.body.scrollTop};
}

4

ドキュメントを基準にした、要素のさまざまな位置のx座標とy座標を取得したい場合。

const getCoords = (element, position) => {
  const { top, left, width, height } = element.getBoundingClientRect();
  let point;
  switch (position) {
    case "top left":
      point = {
        x: left + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "top center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "top right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "center left":
      point = {
        x: left + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "center right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "bottom left":
      point = {
        x: left + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
    case "bottom center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
    case "bottom right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
  }
  return point;
};

使用法

  • getCoords(document.querySelector('selector'), 'center')

  • getCoords(document.querySelector('selector'), 'bottom right')

  • getCoords(document.querySelector('selector'), 'top center')



弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.