web-dev-qa-db-ja.com

HTML要素の位置(X、Y)を取得します

JavaScriptでimgdivなどのHTML要素のXとYの位置を取得する方法を知りたいです。

1271
monaung

正しいアプローチは element.getBoundingClientRect() を使うことです:

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);

あなたが気にする可能性がある限りInternet Explorerはこれをサポートしてきました、そしてそれはついに CSSOM Views で標準化されました。他のすべてのブラウザはそれを採用しました ずっと前

標準的ではありませんが、高さと幅のプロパティを返すブラウザもあります。あなたが古いブラウザの互換性を心配しているならば、最適化された低下する実装のためにこの答えのリビジョンをチェックしてください。

element.getBoundingClientRect()が返す値はビューポートを基準にしています。他の要素に対して相対的に必要な場合は、単純に長方形を他の長方形から引きます。

var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;

alert('Element is ' + offset + ' vertical pixels from <body>');
1544
Andy E

ライブラリは、要素の正確なオフセットを取得するためにある程度の長さがあります。
これは私が試したあらゆる状況で仕事をする簡単な関数です。

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}
var x = getOffset( document.getElementById('yourElId') ).left; 
292
meouw

これは私のために働きました(最高の投票された答えから修正された):

function getOffset(el) {
  const rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.scrollX,
    top: rect.top + window.scrollY
  };
}

これを使って電話することができます

getOffset(element).left

または

getOffset(element).top
197
Adam Grant

Pageに - 少なくとも "DIV"が含まれている場合、meouwによって与えられる関数は現在のページ制限を超えて "Y"値をスローします。正確な位置を見つけるためには、offsetParentとparentNodeの両方を処理する必要があります。

下記のコードを試してください(FF2がチェックされています):


var getAbsPosition = function(el){
    var el2 = el;
    var curtop = 0;
    var curleft = 0;
    if (document.getElementById || document.all) {
        do  {
            curleft += el.offsetLeft-el.scrollLeft;
            curtop += el.offsetTop-el.scrollTop;
            el = el.offsetParent;
            el2 = el2.parentNode;
            while (el2 != el) {
                curleft -= el2.scrollLeft;
                curtop -= el2.scrollTop;
                el2 = el2.parentNode;
            }
        } while (el.offsetParent);

    } else if (document.layers) {
        curtop += el.y;
        curleft += el.x;
    }
    return [curtop, curleft];
};

34
Refik Ayata

ほとんどのブラウザのHTML要素は以下のとおりです。 -

offsetLeft
offsetTop

これらは、レイアウトを持つ最も近い親を基準とした要素の位置を指定します。この親は、offsetParentプロパティからアクセスできます。

IEとFF3は持っています

clientLeft
clientTop

これらのプロパティはそれほど一般的ではなく、親のクライアント領域と一緒に要素の位置を指定します(パディング領域はクライアント領域の一部ですが、ボーダーとマージンはそうではありません)。

33
AnthonyWJones

Element.prototypeに2つのプロパティを追加して、任意の要素の上部/左側を取得できます。

Object.defineProperty( Element.prototype, 'documentOffsetTop', {
    get: function () { 
        return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 );
    }
} );

Object.defineProperty( Element.prototype, 'documentOffsetLeft', {
    get: function () { 
        return this.offsetLeft + ( this.offsetParent ? this.offsetParent.documentOffsetLeft : 0 );
    }
} );

これは次のように呼ばれます。

var x = document.getElementById( 'myDiv' ).documentOffsetLeft;

これはjQueryのoffset().top.leftと結果を比較したデモです: http://jsfiddle.net/ThinkingStiff/3G7EZ/

32
ThinkingStiff

再帰関数を使用せずに、ページに対する相対位置を効率的に取得するには、(IEも含む)

var element = document.getElementById('elementId'); //replace elementId with your element's Id.
var rect = element.getBoundingClientRect();
var elementLeft,elementTop; //x and y
var scrollTop = document.documentElement.scrollTop?
                document.documentElement.scrollTop:document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft?                   
                 document.documentElement.scrollLeft:document.body.scrollLeft;
elementTop = rect.top+scrollTop;
elementLeft = rect.left+scrollLeft;
21

要素のIDを渡すことで左または上を返すことになるので、このようなものはどうでしょうか。また、それらを組み合わせることもできます。

1)左側を探す

function findLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.left + window.scrollX;
} //call it like findLeft('#header');

2)トップを探す

function findTop(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.top + window.scrollY;
} //call it like findTop('#header');

または 3)左と上を一緒に探す

function findTopLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return {top: rec.top + window.scrollY, left: rec.left + window.scrollX};
} //call it like findTopLeft('#header');
19
Alireza

javascriptでしかしたくないなら 、ここにいくつかの 1つのライナー using getBoundingClientRect()

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

最初の行はoffsetLeftがドキュメントを基準にして言うと返します。

2行目では、documentに対してYと言うoffsetTopが返されます。

getBoundingClientRect() は、ウィンドウのビューポートに対する要素の位置を返すJavaScript関数です。

19
Must Keem J

JavaScriptフレームワークを使用すると、ブラウザに依存しない方法でそのような情報を(さらに多くの!)返す機能があります。ここにいくつかあります:

これらのフレームワークで、画像のyピクセル座標を取得するために$('id-of-img').topのようなことをすることができます。

16
Shalom Craimer

jQuery .offset() は、マッチした要素の集合の中で、最初の要素の現在の座標を取得するか、ドキュメントに対する相対座標を設定します。

14
akauppi

私は@ meouwの答えを取り、境界線を考慮に入れるclientLeftに追加し、そして3つのバージョンを作成しました:

getAbsoluteOffsetFromBody - @ meouwと同様に、これはドキュメントの本文またはHTML要素に対する相対的な絶対位置を取得します(Quirksモードによる)

getAbsoluteOffsetFromGivenElement - 指定された要素を基準とした絶対位置(relativeEl)を返します。与えられた要素が要素elを含まなければならないことに注意してください、さもなければこれはgetAbsoluteOffsetFromBodyと同じふるまいをするでしょう。これは、2つの要素が別の(既知の)要素(オプションでノードツリーの上のいくつかのノード)に含まれていて、それらを同じ位置にしたい場合に役立ちます。

getAbsoluteOffsetFromRelative - 最初の親要素を基準とした絶対位置をposition:relativeで返します。これはgetAbsoluteOffsetFromGivenElementと似ていますが、同じ理由からですが、最初に一致した要素までしかありません。

getAbsoluteOffsetFromBody = function( el )
{   // finds the offset of el from the body or html element
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromGivenElement = function( el, relativeEl )
{   // finds the offset of el from relativeEl
    var _x = 0;
    var _y = 0;
    while( el && el != relativeEl && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromRelative = function( el )
{   // finds the offset of el from the first parent with position: relative
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
        if (el != null)
        {
            if (getComputedStyle !== 'undefined')
                valString = getComputedStyle(el, null).getPropertyValue('position');
            else
                valString = el.currentStyle['position'];
            if (valString === "relative")
                el = null;
        }
    }
    return { top: _y, left: _x };
}

それでも特にスクロールに関する問題が解決しない場合は、 http://www.greywyvern.com/?post=331 - を見てみてください。ブラウザは正常に動作すると仮定しても問題ありませんが、それ以外はまったくテストしていません。

10

jQueryを使用している場合は、 dimensionsプラグイン が優れており、必要なものを正確に指定できます。

例えば.

相対位置、絶対位置、パディングなしの絶対位置、パディングあり...

それが続きます、あなたがそれを使ってできることがたくさんあると言いましょう。

加えてjQueryを使うことのボーナスはそれが軽量のファイルサイズと簡単な使用であるということです、あなたはその後それなしでJavaScriptに戻らないでしょう。

8
John_

あなたがjQueryを使っているなら、これは簡単な解決策になるでしょう:

<script>
  var el = $("#element");
  var position = el.position();
  console.log( "left: " + position.left + ", top: " + position.top );
</script>
7
Adam Boostani

これは私が作成できた最高のコードです(jQueryのoffset()とは異なり、iframeでも動作します)。 WebKitは少し違った振る舞いをしているようです。

Meouwのコメントに基づく:

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        // chrome/safari
        if ($.browser.webkit) {
            el = el.parentNode;
        } else {
            // firefox/IE
            el = el.offsetParent;
        }
    }
    return { top: _y, left: _x };
}
7
Ron Reiter

小さいものと小さいものの違い

function getPosition( el ) {
    var x = 0;
    var y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
    x += el.offsetLeft - el.scrollLeft;
    y += el.offsetTop - el.scrollTop;
    el = el.offsetParent;
    }
    return { top: y, left: x };
}

座標の例を見る: http://javascript.info/tutorial/coordinates

7
KingRider

私が見つけた最もクリーンなアプローチは、jQueryのoffsetで使用されている手法を単純化したものです。他の答えのいくつかと同様に、それはgetBoundingClientRectで始まります。次に、スクロール位置を調整するためにwindowdocumentElementを使用し、さらにbodyの余白のようなもの(通常はデフォルト)を使用します。

var rect = el.getBoundingClientRect();
var docEl = document.documentElement;

var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;
var els = document.getElementsByTagName("div");
var docEl = document.documentElement;

for (var i = 0; i < els.length; i++) {

  var rect = els[i].getBoundingClientRect();

  var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
  var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;

  els[i].innerHTML = "<b>" + rectLeft + ", " + rectTop + "</b>";
}
div {
  width: 100px;
  height: 100px;
  background-color: red;
  border: 1px solid black;
}
#rel {
  position: relative;
  left: 10px;
  top: 10px;
}
#abs {
  position: absolute;
  top: 250px;
  left: 250px;
}
<div id="rel"></div>
<div id="abs"></div>
<div></div>
6
James Montagne

私はこのようにしたので、古いブラウザとの互換性がありました。

// For really old browser's or incompatible ones
    function getOffsetSum(elem) {
        var top = 0,
            left = 0,
            bottom = 0,
            right = 0

         var width = elem.offsetWidth;
         var height = elem.offsetHeight;

        while (elem) {
            top += elem.offsetTop;
            left += elem.offsetLeft;
            elem = elem.offsetParent;
        }

         right = left + width;
         bottom = top + height;

        return {
            top: top,
            left: left,
            bottom: bottom,
            right: right,
        }
    }

    function getOffsetRect(elem) {
        var box = elem.getBoundingClientRect();

        var body = document.body;
        var docElem = document.documentElement;

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

        var clientTop = docElem.clientTop;
        var clientLeft = docElem.clientLeft;


        var top = box.top + scrollTop - clientTop;
        var left = box.left + scrollLeft - clientLeft;
        var bottom = top + (box.bottom - box.top);
        var right = left + (box.right - box.left);

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

    function getOffset(elem) {
        if (elem) {
            if (elem.getBoundingClientRect) {
                return getOffsetRect(elem);
            } else { // old browser
                return getOffsetSum(elem);
            }
        } else
            return null;
    }

JavaScriptでの座標の詳細はこちら: http://javascript.info/tutorial/coordinates

5
Bojan Kseneman

これは非常に多くの答えの下で失われる可能性が非常に高いですが、ここでのトップの解決策は私のために働いていませんでした。
私が言うことができる限り、他の答えのどれも助けにはならなかったでしょう。

状況
HTML5ページで、私はヘッダの内側にnav要素であるメニューを持っていました(THEヘッダではなく別の要素のヘッダ)。
ユーザーがスクロールしたときにナビゲーションが一番上に固定されるようにしたいのですが、これ以前はヘッダーが絶対位置に設定されていました(したがって、他のものを少しオーバーレイすることもできます)。
これは絶対位置の要素なので、.offsetTopは変更されないため、上記の解決策では変更が発生することはありません。加えて、.scrollTopプロパティは単に一番上の要素の一番上でした...つまり0と言い、常に0になります。
これら2つを利用して実行したテスト(およびgetBoundingClientRectの結果と同じ)では、ナビゲーションバーの上部が表示可能なページの上部にスクロールされたことがあるかどうかはわかりません。スクロール中に同じ番号が発生した場合)。

溶液
私のための解決策は利用していました

window.visualViewport.pageTop

PageTopプロパティの値は画面の表示可能なセクションを反映するので、表示可能領域の境界を基準にして要素がどこにあるかを追跡できます。

言うまでもありませんが、スクロールを扱っているときはいつでも、スクロールされている要素の動きにプログラムで応答するためにこのソリューションを使用することを期待しています。
それが他の誰かに役立つことを願っています。
重要なメモ: これは現在ChromeとOperaで動作しているように見えますが、Firefoxでは動作しません(6-2018) ... FirefoxでvisualViewportがサポートされるまで彼らがすぐにやることを願っています...それは他のものよりずっと理にかなっています)。


更新:
この解決策に関するメモです。
「...スクロールされている要素の移動にプログラム的に対応する」状況では、私が発見したものが非常に有益であることがまだわかります。適用可能です。私が持っていた問題のためのより良い解決策は要素に position:sticky を設定するためにCSSを使うことでした。スティッキを使用すると、JavaScriptを使用しなくても要素を上に表示させることができます(注:要素をfixedに変更するほど効果的に機能しない場合がありますが、ほとんどの用途でスティッキアプローチはおそらく優れています)。

UPDATE01:
それで、私は別のページのために私が穏やかに複雑なスクロールセットアップ(視差とメッセージの一部として過去にスクロールする要素)の要素の位置を検出する必要があるという要件があると気づきました。そのシナリオでは、次のことが、いつやるべきかを判断するために利用した価値を提供することに気付きました。

  let bodyElement = document.getElementsByTagName('body')[0];
  let elementToTrack = bodyElement.querySelector('.trackme');
  trackedObjPos = elementToTrack.getBoundingClientRect().top;
  if(trackedObjPos > 264)
  {
    bodyElement.style.cssText = '';
  }

この答えがもっと広く役立つことを願います。

3
MER

私は、ユーザーがテーブル行のどのリンクをクリックしたかに応じて、ブートストラップ2モーダルを配置するためにAndy Eのソリューションを使用しました。このページはTapestry 5のページで、以下のJavaScriptがJavaページクラスにインポートされています。

javaScript:

function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset   = elemRect.top - bodyRect.top;
offset   = offset + 20;
$('#serviceLineModal').css("top", offset);

}

私のモーダルコード:

<div id="serviceLineModal" class="modal hide fade add-absolute-position" data-backdrop="static" 
 tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="top:50%;">
<div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
    <h3 id="myModalLabel">Modal header</h3>
</div>

<div class="modal-body">
    <t:zone t:id="modalZone" id="modalZone">
        <p>You selected service line number: ${serviceLineNumberSelected}</p>
    </t:zone>
</div>

<div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <!-- <button class="btn btn-primary">Save changes</button> -->
</div>

ループ内のリンク:

<t:loop source="servicesToDisplay" value="service" encoder="encoder">
<tr style="border-right: 1px solid black;">       
    <td style="white-space:nowrap;" class="add-padding-left-and-right no-border"> 
        <a t:type="eventLink" t:event="serviceLineNumberSelected" t:context="service.serviceLineNumber" 
            t:zone="pageZone" t:clientId="modalLink${service.serviceLineNumber}"
            onmouseover="setLinkPosition(this);">
            <i class="icon-chevron-down"></i> <!-- ${service.serviceLineNumber} -->
        </a>
    </td>

そしてページクラスのJavaコード:

void onServiceLineNumberSelected(String number){
    checkForNullSession();
    serviceLineNumberSelected = number;
    addOpenServiceLineDialogCommand();
    ajaxResponseRenderer.addRender(modalZone);
}

protected void addOpenServiceLineDialogCommand() {
    ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
        @Override
        public void run(JavaScriptSupport javascriptSupport) {
            javascriptSupport.addScript("$('#serviceLineModal').modal('show');");
        }
    });
}

これが誰かに役立つことを願っています。この投稿は助けてくれました。

2
Mark Espinoza

要素の総オフセットを取得するには、すべての親オフセットを再帰的に合計します。

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

この効用関数では、dom要素の上部オフセットの合計は次のようになります。

el.offsetTop + getParentOffsets(el);
2
Kevin K.

多くの調査とテストの結果、これはうまくいくようです

function getPosition(e) {
    var isNotFirefox = (navigator.userAgent.toLowerCase().indexOf('firefox') == -1);
    var x = 0, y = 0;
    while (e) {
        x += e.offsetLeft - e.scrollLeft + (isNotFirefox ? e.clientLeft : 0);
        y += e.offsetTop - e.scrollTop + (isNotFirefox ? e.clientTop : 0);
        e = e.offsetParent;
    }
    return { x: x + window.scrollX, y: y + window.scrollY };
}

http://jsbin.com/xuvovalifo/edit?html,js,output を参照してください。

1
kernowcode

私もこれを捨てることを考えていました。
私は古いブラウザでそれをテストすることができませんでした、しかしそれはトップ3の最新のもので働きます:)

Element.prototype.getOffsetTop = function() {
    return ( this.parentElement )? this.offsetTop + this.parentElement.getOffsetTop(): this.offsetTop;
};
Element.prototype.getOffsetLeft = function() {
    return ( this.parentElement )? this.offsetLeft + this.parentElement.getOffsetLeft(): this.offsetLeft;
};
Element.prototype.getOffset = function() {
    return {'left':this.getOffsetLeft(),'top':this.getOffsetTop()};
};
1
Duncan

左と上に対するdivの位置を取得

  var Elm = $('#div_id');  //get the div
  var posY_top = Elm.offset().top;  //get the position from top
  var posX_left = Elm.offset().left; //get the position from left 
0
Vishal

異なるブラウザは異なる方法でボーダー、パディング、マージンなどをレンダリングしているので。私はあなたが正確な次元で欲しいすべてのルート要素の中の特定の要素の上と左の位置を検索するための小さな関数を書きました:

function getTop(root, offset) {
    var rootRect = root.getBoundingClientRect();
    var offsetRect = offset.getBoundingClientRect();
    return offsetRect.top - rootRect.top;
}

左の位置を取得するには、返さなければなりません:

    return offsetRect.left - rootRect.left;
0
samadadi
/**
 *
 * @param {HTMLElement} el
 * @return {{top: number, left: number}}
 */
function getDocumentOffsetPosition(el) {
    var position = {
        top: el.offsetTop,
        left: el.offsetLeft
    };
    if (el.offsetParent) {
        var parentPosition = getDocumentOffsetPosition(el.offsetParent);
        position.top += parentPosition.top;
        position.left += parentPosition.left;
    }
    return position;
}

ThinkingStiff答え に感謝します。これは別バージョンです。

0
Văn Quyết