JavaScriptでimg
やdiv
などのHTML要素のXとYの位置を取得する方法を知りたいです。
正しいアプローチは 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>');
ライブラリは、要素の正確なオフセットを取得するためにある程度の長さがあります。
これは私が試したあらゆる状況で仕事をする簡単な関数です。
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;
これは私のために働きました(最高の投票された答えから修正された):
function getOffset(el) {
const rect = el.getBoundingClientRect();
return {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY
};
}
これを使って電話することができます
getOffset(element).left
または
getOffset(element).top
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];
};
ほとんどのブラウザのHTML要素は以下のとおりです。 -
offsetLeft
offsetTop
これらは、レイアウトを持つ最も近い親を基準とした要素の位置を指定します。この親は、offsetParentプロパティからアクセスできます。
IEとFF3は持っています
clientLeft
clientTop
これらのプロパティはそれほど一般的ではなく、親のクライアント領域と一緒に要素の位置を指定します(パディング領域はクライアント領域の一部ですが、ボーダーとマージンはそうではありません)。
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/
再帰関数を使用せずに、ページに対する相対位置を効率的に取得するには、(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;
要素の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');
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関数です。
jQuery .offset() は、マッチした要素の集合の中で、最初の要素の現在の座標を取得するか、ドキュメントに対する相対座標を設定します。
私は@ 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 - を見てみてください。ブラウザは正常に動作すると仮定しても問題ありませんが、それ以外はまったくテストしていません。
jQueryを使用している場合は、 dimensionsプラグイン が優れており、必要なものを正確に指定できます。
例えば.
相対位置、絶対位置、パディングなしの絶対位置、パディングあり...
それが続きます、あなたがそれを使ってできることがたくさんあると言いましょう。
加えてjQueryを使うことのボーナスはそれが軽量のファイルサイズと簡単な使用であるということです、あなたはその後それなしでJavaScriptに戻らないでしょう。
あなたがjQueryを使っているなら、これは簡単な解決策になるでしょう:
<script>
var el = $("#element");
var position = el.position();
console.log( "left: " + position.left + ", top: " + position.top );
</script>
これは私が作成できた最高のコードです(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 };
}
小さいものと小さいものの違い
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 };
}
私が見つけた最もクリーンなアプローチは、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;
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>
私はこのようにしたので、古いブラウザとの互換性がありました。
// 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
これは非常に多くの答えの下で失われる可能性が非常に高いですが、ここでのトップの解決策は私のために働いていませんでした。
私が言うことができる限り、他の答えのどれも助けにはならなかったでしょう。
状況:
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 = '';
}
この答えがもっと広く役立つことを願います。
私は、ユーザーがテーブル行のどのリンクをクリックしたかに応じて、ブートストラップ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');");
}
});
}
これが誰かに役立つことを願っています。この投稿は助けてくれました。
要素の総オフセットを取得するには、すべての親オフセットを再帰的に合計します。
function getParentOffsets(el): number {
if (el.offsetParent) {
return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
return 0;
}
}
この効用関数では、dom要素の上部オフセットの合計は次のようになります。
el.offsetTop + getParentOffsets(el);
多くの調査とテストの結果、これはうまくいくようです
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 };
}
私もこれを捨てることを考えていました。
私は古いブラウザでそれをテストすることができませんでした、しかしそれはトップ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()};
};
左と上に対する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
異なるブラウザは異なる方法でボーダー、パディング、マージンなどをレンダリングしているので。私はあなたが正確な次元で欲しいすべてのルート要素の中の特定の要素の上と左の位置を検索するための小さな関数を書きました:
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
左の位置を取得するには、返さなければなりません:
return offsetRect.left - rootRect.left;
/**
*
* @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 を 答え に感謝します。これは別バージョンです。