私は、次のようなHTML要素のXとYの位置を取得する方法を知りたいimg
とdiv
、ブラウザウィンドウにはJavaScriptに相対。
私は、次のようなHTML要素のXとYの位置を取得する方法を知りたいimg
とdiv
、ブラウザウィンドウにはJavaScriptに相対。
回答:
正しいアプローチは以下を使用すること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>');
<body>
ただし、CSSをリセットするとからマージンが削除されることに注意してください。
element.getBoundingClientRect().top
position: fixed
フォーカスされた入力要素が含まれ、仮想キーボードが上にスライドした場合、iOS(iPhone 8)の要素の場合、正しい上部オフセットを返しません。たとえば、ウィンドウの上部からの実際のオフセットが200pxの場合、それは420pxとして報告されます。ここで、220pxは仮想キーボードの高さです。要素を設定position: absolute
し、固定した場合と同じ位置に配置すると、正しい200pxが得られます。私はこれに対する解決策を知りません。
ライブラリは、要素の正確なオフセットを取得するために、いくつかの長さに行きます。
これは、私が試したあらゆる状況で機能する単純な関数です。
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
div
cssを使用して中央に配置されているときにこのソリューションのみが機能しますtop:50%, left:50%; transform:translate(-50%, -50%);
...優れています。@ScottBiggsの質問に同意します。論理は単純さを求めることです。
rect
使用してvar
、let
またはconst
。それ以外の場合は、として定義されwindow.rect
ます。
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)
要素の中央位置を返します
あなたがそれを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関数です。
ほとんどのブラウザのHTML要素は次のようになります:-
offsetLeft
offsetTop
これらは、レイアウトを持つ最も近い親を基準にした要素の位置を指定します。多くの場合、この親は、offsetParentプロパティを使用してアクセスできます。
IEとFF3には
clientLeft
clientTop
これらのプロパティはあまり一般的ではなく、親のクライアント領域で要素の位置を指定します(埋め込み領域はクライアント領域の一部ですが、境界線とマージンはそうではありません)。
ページに少なくとも「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];
};
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
と.left
:http://jsfiddle.net/ThinkingStiff/3G7EZ/は、
Element.prototype
は一般的に悪い考えと考えられています。コードの保守が非常に難しくなります。また、このコードはスクロールを考慮していません。
再帰関数を使用せずに、ページに対する相対位置を効率的に取得するには:(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フレームワークを使用することで、より良いサービスが提供される可能性があります。ここにいくつかあります:
これらのフレームワークを使用すると、次のようなことができます
$('id-of-img').top
。画像のyピクセル座標を取得する。
jQuery .offset()は、ドキュメントに対して、最初の要素の現在の座標を取得するか、一致した要素のセット内のすべての要素の座標を設定します。
私は@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つ以上ありました。、残りはまったくテストしていません。
jQueryを使用する場合、dimensionsプラグインは優れており、必要なものを正確に指定できます。
例えば
相対位置、絶対位置、パディングなしの絶対位置、パディングあり...
それが続く、それであなたができることがたくさんあるとだけ言ってみましょう。
さらに、jQueryを使用することの利点は、ファイルサイズが軽量で使いやすいことです。その後、それがないとJavaScriptに戻ることはできません。
これは私が作成したコードの中で最高のものです(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を使用している場合、これは簡単な解決策になる可能性があります。
<script>
var el = $("#element");
var position = el.position();
console.log( "left: " + position.left + ", top: " + position.top );
</script>
小と小の違い
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
<svg>
要素は、例えば、持っていないoffsetLeft
、offsetTop
とoffsetParent
性質。
DIV
かIMG
、そうではないSVG
。「座標例を見る」を表示しますか?オブジェクトsvgがgetOffsetRectの位置呼び出しであることがわかり、オブジェクトの作業に依存します。
私が見つけた最もクリーンなアプローチは、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;
これは非常に多くの回答の下部で失われる可能性が非常に高いですが、ここでの上位のソリューションは私にとってはうまくいきませんでした。
私が知る限りでは、他のどの回答も役に立たなかったでしょう。
状況:
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 = '';
}
この回答がより広く役立つことを願っています。
私はこのようにしたので、古いブラウザとの互換性がありました。
// 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をご覧ください。
/**
*
* @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に感謝します。これはその別のバージョンにすぎません。
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');");
}
});
}
これが誰かを助けることを願って、この投稿が助けてくれました。
多くの研究とテストの後、これはうまくいくようです
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()};
};
ブラウザーによって、ボーダー、パディング、マージンなどのレンダリング方法が異なるためです。正確な次元で必要なすべてのルート要素の特定の要素の上部と左側の位置を取得するための小さな関数を作成しました。
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
左の位置を取得するには、次を返す必要があります。
return offsetRect.left - rootRect.left;
左と上を基準にした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
el.offsetTop
とel.offsetLeft
(OPは...あなたの答えはjQueryのいずれかを使用して、なぜ私はわからないんだけど... jQueryのについては何も言うことはありません)