ブラウザウィンドウを基準としたHTML要素の位置(X、Y)を取得する


1570

私は、次のようなHTML要素のXとYの位置を取得する方法を知りたいimgdiv、ブラウザウィンドウにはJavaScriptに相対。


134
何に対して?
AnthonyWJones 2009年

4
ie5,6,7に矛盾があるすべてのブラウザーで機能するこれらの7行のコードを使用していました(問題があることを覚えていません... docタイプの可能性があります)... quirksmode.org/js/findpos。 htmlと私は何年もの間それをたくさん使ってきました。sombodyは、もしあれば欠陥を指摘することができます。
Jayapal Chandran 2015

98
@AnthonyWJones、私はあなたが徹底的な喜びを必要としていたと思いますが、OPが最も一般的なケースを参照するか、ブラウザのウィンドウ座標を参照することは、常に指定されていないときはいつものように明白です。
モート

7
@Mote、いや、それはそれほど明白ではありません。推論、主観性、虚偽の公理は別としてください。ビューポートまたはページの上部(別名document.documentElement)を基準にすることができます。
Andre Figueiredo

15
最も一般的なデフォルト設定は推論ではなく、論理的な進行であるため、ウィンドウに相対的であるか、または「ページのトップ」があなたが言うとおりの言葉かもしれません。ゲーム理論では、それはシェリングポイントと呼ばれる概念として体系化されています。最も一般的なケースを意味しない場合は、必ず指定してください。
モート2017年

回答:


1796

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

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

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

一部のブラウザは高さと幅のプロパティも返しますが、これは非標準です。古いブラウザーの互換性が心配な場合は、この回答の改訂版をチェックして、最適化されたパフォーマンス低下の実装を確認してください。

によって返される値はelement.getBoundingClientRect()、ビューポートを基準にしています。別の要素と比較して必要な場合は、単純に1つの長方形を他の長方形から差し引きます。

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

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

143
JS座標上非常に興味深い記事。この記事は、SOのどこにも言及されていません。それは..
e2-e4

6
動作しません...本体の8pxのマージンのため、縦と横に8ピクセルずれています。Meouwのソリューションは完全に機能します。あなたが望むなら、私は問題を実証するための小さなテストを持っています。
CpnCrunch 14

3
実際、あなたが実際に何を調整したいのかによります。質問は少しあいまいです。ビューポートまたはbody要素を基準にした座標のみが必要な場合、あなたの答えは正しいですが、要素の絶対的な位置(ほとんどの人が望んでいるものだと私が想像するもの)が必要な場合には役に立ちません。meouwの答えは、 '-scrollLeft'および '-scrollTop'ビットを削除しない限り、それも与えません。
CpnCrunch 14

4
@CpnCrunch:私はあなたが今何を言っているのか分かります 私の答えの後半について言及していることに気づかなかった。ボディにマージンがある場合、バウンディングボックスは、それぞれの側でそのピクセル数だけオフセットされます。その場合、ボディ座標から計算されたマージンスタイルを差し引く必要があります。<body>ただし、CSSをリセットするとからマージンが削除されることに注意してください。
アンディE

3
element.getBoundingClientRect().topposition: fixedフォーカスされた入力要素が含まれ、仮想キーボードが上にスライドした場合、iOS(iPhone 8)の要素の場合、正しい上部オフセットを返しません。たとえば、ウィンドウの上部からの実際のオフセットが200pxの場合、それは420pxとして報告されます。ここで、220pxは仮想キーボードの高さです。要素を設定position: absoluteし、固定した場合と同じ位置に配置すると、正しい200pxが得られます。私はこれに対する解決策を知りません。
ジャニスElmeris

327

ライブラリは、要素の正確なオフセットを取得するために、いくつかの長さに行きます。
これは、私が試したあらゆる状況で機能する単純な関数です。

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; 

14
変更:el = el.parentNodeに:el = el.offsetParent; ネストされたiframeでも機能するようです...それはあなたが意図したことだと思いますか?
アダム

4
このソリューションは不完全です。divに太い境界線を付けて、数回入れ子にしてみてください。Firefoxのどのバージョン(2-5)でも、(標準準拠モードであっても)境界線の幅が外れます。
ck_ 2011

3
el.totalOffsetLeftやtotalOffsetTop関数のように、それを行うためのより明確な方法はありませんか?jQueryには確かにこのオプションがありますが、これには公式の方法がないのは残念です。DOM4を待つ必要がありますか?私はHTML5キャンバスアプリケーションを構築しているので、最善の解決策は、キャンバス要素をiframeに挿入して、要素をクリックしたときにclientXおよびclientYで実際の座標を取得できるようにすることだと思います。
baptx

1
@Adamとmeouwは、最初のコードブロックが間違っていると言っていますか?次に、それを完全に削除してみませんか?(この質問は、何年にもわたってかなりの視聴者に見られました。間違っている場合は削除するのが良いでしょうか?)
Arjan

2
@baptx:私はこれが遅い返答であることを知っていますが、あなたのコメントをもっと早く見ました より標準に準拠した代替案については、以下の私の回答を参照してください。ブラウザーが長い間サポートしてきたため、フォールバックコードは実際には必要ありません。
アンディE

242

これは私のために働きました(最高投票の回答から変更されました):

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

これを使用して呼び出すことができます

getOffset(element).left

または

getOffset(element).top

1
要素がdivcssを使用して中央に配置されているときにこのソリューションのみが機能しますtop:50%, left:50%; transform:translate(-50%, -50%);...優れています。@ScottBiggsの質問に同意します。論理は単純さを求めることです。
nelek

3
おそらく勝者ではないため、Andy Eのソリューションと同じですが、古いブラウザでは機能しません<IE9
niltoid

getBoundingClientRectを使用すると、パフォーマンスチャートに大幅な再描画スパイクが発生します
フルンベルト

1
あなたは定義する必要がありますrect使用してvarletまたはconst。それ以外の場合は、として定義されwindow.rectます。
hev1 2018

2
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)要素の中央位置を返します
abhishake

97

あなたがそれをjavascriptのみで実行したい場合は、ここでいくつかのライナー を使用していますgetBoundingClientRect()

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

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

最初の行はoffsetTop、ドキュメントに対してY を返します。2行目はoffsetLeft、ドキュメントに対して相対的なX を返します。

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


2
これが解決策です。ここには長いコードbsはありません。理解可能で、非常に正確です。
E Alexis MT

2
要素がスクロール可能な要素内にある場合はどうなりますか?それを行う唯一の方法は、他の回答が示唆するように、すべての親要素のoffsetTopを合計することです
Dmitri Pisarev

Dmitriが述べているように、これは正しくなく、非常に欠陥があります。賛成票の数が多すぎてはいけません。ドキュメント自体をスクロールできるため、常にスクロール可能な要素にも含まれます。つまり、ドキュメント全体がビューポートに収まらない限り、ユーザーがメインウィンドウをスクロールした場合は常に正しく表示されません。
レフ

46

ほとんどのブラウザのHTML要素は次のようになります:-

offsetLeft
offsetTop

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

IEとFF3には

clientLeft
clientTop

これらのプロパティはあまり一般的ではなく、親のクライアント領域で要素の位置を指定します(埋め込み領域はクライアント領域の一部ですが、境界線とマージンはそうではありません)。


36

ページに少なくとも「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];
};

1
他のソリューションと同様に、FF 24.4を使用しても、配置レイアウトの一部として境界線の幅が存在する場合、上記のコードは機能しません。
rob

あなたは命の恩人です。私はいくつかのかなり深いGWTバグに現在取り組んでおり、これをJSNIメソッドでスローするとすべての問題が解決します!!
ウィルバーン

35

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

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.lefthttp://jsfiddle.net/ThinkingStiff/3G7EZ/は、


14
変更Element.prototypeは一般的に悪い考えと考えられています。コードの保守が非常に難しくなります。また、このコードはスクロールを考慮していません。
Jared Forsyth

23

再帰関数を使用せずに、ページに対する相対位置を効率的に取得するには:(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;

すべての重要なscrollTop / scrollLeftを含めると、この答えはもう少し正確になります。
scunliffe 2014

19

要素の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');

16

ブラウザに依存しない方法でそのような情報を返す関数(そしてそれ以上のもの!)を返すJavaScriptフレームワークを使用することで、より良いサービスが提供される可能性があります。ここにいくつかあります:

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


2
@Costaそれらはすべてこの種の関数を使用しますが、これは進化するフィールドです。異なるブラウザーは仕様に異なる方法で準拠しているためです。コードの多くは、問題のある「修正」を扱います。あなたは本当にソースコードを見るべきです。
Shalom Craimer 2013年

18
@scraimer:jQueryとYUIはフレームワークではありません !!! これらはライブラリです!同じではありません。jquery.comの引用:「jQueryは高速で小さく、機能が豊富なJavaScript ライブラリです。」yuilibrary.comを引用する(URLに「魔法の」単語も表示されます...):「YUIは、
Sk8erPeter 2013年

29
したがって、この単純なタスクのためだけに巨大なライブラリを使用する必要がありますか?必要はありません。私はjsで何かをしたいたびに、これらのjQueryソリューションを手に入れるのが嫌いです。jQueryはJSではありません!
Opptatt Jobber 2013

1
@OpptattJobber同意します... JQueryはJavaScriptではありません。JavaScriptに依存していますが、まったく別のプログラミング言語です。
Nick Manning

5
@NickManning新しい言語ではなく、互換性とパフォーマンスの回避策をコードに直接記述する必要をなくすDOMの抽象化レイヤーです。jQueryを使用しない場合は、いずれかのタイプの抽象化レイヤーを使用する必要があります。
ジンマン14

15

jQuery .offset()は、ドキュメントに対して、最初の要素の現在の座標を取得するか、一致した要素のセット内のすべての要素の座標を設定します。


何らかの理由で、IEでは他のブラウザーと同じ結果が得られません。IEではウィンドウに対して相対的な位置を示していると思うので、スクロールすると、IEで他と比較して異なる結果が表示されます
Abdul Rahim Haddad

1
offset()は、少なくともAndroid Chromeではズームによって混乱するため、役に立ちません。stackoverflow.com/a/11396681/1691517は、ズーム許容方法を示しています。
TimoKähkönen15年

10

私は@meouwの回答を取り、境界線を許可するclientLeftに追加して、3つのバージョンを作成しました。

getAbsoluteOffsetFromBody-@meouwと同様に、これはドキュメントの本文またはHTML要素に対する相対位置を取得します(互換モードに応じて異なります)

getAbsoluteOffsetFromGivenElement-指定された要素(relativeEl)に相対的な絶対位置を返します。指定された要素には要素elが含まれている必要があります。そうでない場合、これはgetAbsoluteOffsetFromBodyと同じように動作します。これは、2つの要素が別の(既知の)要素(オプションでノードツリーのいくつかのノード)内に含まれていて、それらを同じ位置にしたい場合に便利です。

getAbsoluteOffsetFromRelative-相対位置を持つ最初の親要素に相対的な絶対位置を返します。これは、同じ理由で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を参照してみてください。ブラウザが動作することを前提として問題ないはずの、getStyleの疑わしいコードが1つ以上ありました、残りはまったくテストしていません。


興味深い...しかしEdgeでは、スクロールするとgetAbsoluteOffsetFromBody(element).topが異なる値を返しますが、Chromeではスクロールしても一貫性が保たれます。Edgeがスクロール位置で調整しているようです。要素が非表示にスクロールされると、負の値が表示されます。
ノーマン

getAbsoluteOffsetFromRelativeが私の一日を作りました、私はブートストラップのJavascriptなしでブートストラップツールチップを再現しなければなりませんでした、それは私を大いに助けました。
Nolyurn

Meouwがユーザー名を変更した場合に備えて、回答へのリンク:stackoverflow.com/a/442474/3654837。(私はこの古いスレッドをぶつけたくないので、ええ、私はコメントに入れます)
Mukyuu

8

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

例えば

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

それが続く、それであなたができることがたくさんあるとだけ言ってみましょう。

さらに、jQueryを使用することの利点は、ファイルサイズが軽量で使いやすいことです。その後、それがないとJavaScriptに戻ることはできません。


8

これは私が作成したコードの中で最高のものです(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 };
}

jQueryを使用する必要があることに注意してください$.browser.webkitnavigator.userAgentpureで同じことを行うには、いじってみる必要がありますJavaScript
SP

2
$ .browserは、jQueryの最新バージョンでは利用できなくなりました
Gus

残念ながらFF 24.4を使用しても、配置レイアウトの一部として境界線の幅が存在する場合、上記のコードは機能しません。
rob

8

jQueryを使用している場合、これは簡単な解決策になる可能性があります。

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

8

小と小の違い

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


残念ながら、これは最新のHTMLドキュメント内にあるすべての要素に対して機能するわけではありません。組み込み<svg>要素は、例えば、持っていないoffsetLeftoffsetTopoffsetParent性質。
Jonathan Eunice

その正義DIVIMG、そうではないSVG。「座標例を見る」を表示しますか?オブジェクトsvgがgetOffsetRectの位置呼び出しであることがわかり、オブジェクトの作業に依存します。
KingRider 2016年

7

私が見つけた最もクリーンなアプローチは、jQueryで使用されている手法の簡易バージョンですoffset。で始まる他のいくつかの回答と同様にgetBoundingClientRect、次に、windowとを使用して、documentElementスクロール位置や、マージン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;


6

これは非常に多くの回答の下部で失われる可能性が非常に高いですが、ここでの上位のソリューションは私にとってはうまくいきませんでした。
私が知る限りでは、他のどの回答も役に立たなかったでしょう。

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

解決
策私にとっての解決策は

window.visualViewport.pageTop

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

言うまでもないだろうが、スクロールを扱っているときはいつでも、このソリューションを使用して、スクロールされている要素の動きにプログラムで応答することを期待している。
それが他の誰かを助けることを願っています。
重要な注意:これはChromeとOperaで現在動作しているようで、Firefox(6-2018)では動作しません。FirefoxがvisualViewportをサポートするまで、この方法は使用しないことをお勧めします(すぐに動作することを願っています...残りよりも意味があります)。


更新:
このソリューションに関するメモです。
「スクロールされている要素の動きにプログラムで応答する」ような状況では、私が発見したものは非常に貴重であることがわかりました。該当します。私が抱えていた問題のより良い解決策は、CSSを使用して位置を設定することでした:sticky要素に。粘着性の使用あなたはjavascriptを使用せずに、上部の要素の滞在を持つことができます(注:これは仕事の固定が、ほとんどの用途のために粘着性のアプローチは、可能性の高い優れただろうに要素を変える効果的ではないだろうと同じくらいの時間があります)

:UPDATE01
だから私は気づいは、別のページでは、少し複雑なスクロール設定(視差とメッセージの一部として過去にスクロールする要素)で要素の位置を検出する必要があるという要件がありました。そのシナリオで、次のことが、何かをするときに決定するために利用した価値を提供していることに気付きました。

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

この回答がより広く役立つことを願っています。


あなたがクリックしたときに、これは非常に可能性が高いので、多くの答えの上部にされるアクティブな答えをソートする
ルッキ

@lucchi:Dええと、@ topのテキストを削除できると思います...でも、もう一度この問題に遭遇し、自分の問題のより良い解決策が見つかることに気付きました...私の答えは、より完全な答えへの脚注。私の要件は、他の答えがうまくいかなかったのと同じくらい一般的ではなかったのではないかと思いますか?
MER

1
私はとにかくあなたの答えに感謝します、それはあなたに何かを書いたことを気づいているだれでも気づくだろうとあなたに言うだけでした。あなたは....一人ではありません
ルッキ

5

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

// 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をご覧ください。


4

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

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

このユーティリティ関数を使用すると、dom要素の上部オフセットの合計は次のようになります。

el.offsetTop + getParentOffsets(el);

3
/**
 *
 * @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に感謝します。これはその別のバージョンにすぎません。


2

Andy Eのソリューションを使用して、ユーザーがクリックしたテーブル行のリンクに応じて、ブートストラップ2モーダルを配置しました。このページは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');");
        }
    });
}

これが誰かを助けることを願って、この投稿が助けてくれました。


このjsコードは私を助けました、私は複数のプレースホルダーを使用した古いwebformsアプリを持っています.aspxページをインジェクトし、DOMツリー全体が破壊されているため、ビューポートに取得するために作成しているポップアップボックスのappendChild()の方法を理解できませんでした複数のプレースホルダーと誤ったマークアップ。body.getBoundingClientRect()を使用してから、その上部を配置に使用する必要がありました。ありがとう。
ブラッドマーティン

1

多くの研究とテストの後、これはうまくいくようです

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

私もこれを捨てると思いました。
古いブラウザではテストできませんでしたが、最新の上位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()};
};

0

ブラウザーによって、ボーダー、パディング、マージンなどのレンダリング方法が異なるためです。正確な次元で必要なすべてのルート要素の特定の要素の上部と左側の位置を取得するための小さな関数を作成しました。

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

左の位置を取得するには、次を返す必要があります。

    return offsetRect.left - rootRect.left;

-1

左と上を基準にした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 

下と右はoffset()のプロパティではないため、反対票を投じました
MacroMan、2018年

@MacroMan、私はあなたの決定を尊重しますが、私はすでにテキストで「下と右のコードはテストされていません」と説明しました。また、私はすぐにコードを更新します。
Vishal

私はそれがだと思うel.offsetTopel.offsetLeft(OPは...あなたの答えはjQueryのいずれかを使用して、なぜ私はわからないんだけど... jQueryのについては何も言うことはありません)
mesqueeb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.