Ich möchte wissen, wie man die X- und Y-Position von HTML-Elementen wie img
und div
in JavaScript ermittelt.
Der richtige Ansatz ist element.getBoundingClientRect()
:
var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);
Internet Explorer unterstützt dies seit jeher und wurde schließlich in CSSOM Views standardisiert. Alle anderen Browser haben es übernommen vor langer Zeit .
Einige Browser geben auch Eigenschaften für Höhe und Breite zurück, obwohl dies nicht dem Standard entspricht. Wenn Sie sich Sorgen über die Kompatibilität älterer Browser machen, überprüfen Sie die Überarbeitungen dieser Antwort auf eine optimierte, nachteilige Implementierung.
Die von element.getBoundingClientRect()
zurückgegebenen Werte beziehen sich auf das Ansichtsfenster. Wenn Sie es relativ zu einem anderen Element benötigen, subtrahieren Sie einfach ein Rechteck vom anderen:
var bodyRect = document.body.getBoundingClientRect(),
elemRect = element.getBoundingClientRect(),
offset = elemRect.top - bodyRect.top;
alert('Element is ' + offset + ' vertical pixels from <body>');
Die Bibliotheken sind auf einige Längen beschränkt, um genaue Offsets für ein Element zu erhalten.
Hier ist eine einfache Funktion, die die Arbeit unter allen Umständen erledigt, die ich ausprobiert habe.
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;
Das hat bei mir geklappt (geändert von der Antwort mit der höchsten Bewertung):
function getOffset(el) {
const rect = el.getBoundingClientRect();
return {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY
};
}
Damit können wir anrufen
getOffset(element).left
oder
getOffset(element).top
HTML-Elemente in den meisten Browsern haben:
offsetLeft
offsetTop
Diese geben die Position des Elements relativ zum nächsten übergeordneten Element mit Layout an. Auf dieses übergeordnete Element kann häufig über die Eigenschaft offsetParent zugegriffen werden.
IE und FF3 haben
clientLeft
clientTop
Diese Eigenschaften sind seltener. Sie geben eine Elementposition mit dem übergeordneten Kundenbereich an (gepolsterter Bereich ist Teil des Kundenbereichs, Rahmen und Rand jedoch nicht).
Wenn die Seite - zumindest - ein "DIV" enthält, wirft die von meouw angegebene Funktion den "Y" -Wert über die aktuellen Seitengrenzen hinaus. Um die genaue Position zu finden, müssen Sie sowohl offsetParents als auch parentNodes verarbeiten.
Probieren Sie den unten angegebenen Code aus (er ist auf FF2 geprüft):
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];
};
Sie können Element.prototype
zwei Eigenschaften hinzufügen, um den oberen/linken Rand eines Elements zu erhalten.
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 );
}
} );
Das nennt man so:
var x = document.getElementById( 'myDiv' ).documentOffsetLeft;
Hier ist eine Demo, die die Ergebnisse mit jQueries offset().top
und .left
vergleicht: http://jsfiddle.net/ThinkingStiff/3G7EZ/
Wenn Sie wollen, dass es nur in Javascript gemacht wird , hier sind einige Einzeiler mit getBoundingClientRect()
window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X
window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y
Die erste Zeile gibt offsetLeft
say X relativ zum Dokument zurück.
Die zweite Zeile gibt offsetTop
say Y relativ zum Dokument zurück.
getBoundingClientRect()
ist eine Javascript-Funktion, die die Position des Elements relativ zum Ansichtsfenster des Fensters zurückgibt.
So rufen Sie die Position relativ zur Seite effizient und ohne Verwendung einer rekursiven Funktion ab: (enthält auch 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;
Wie wäre es mit so etwas, wenn Sie die ID des Elements übergeben und es wird links oder oben zurückgegeben, können wir sie auch kombinieren:
1) finde links
function findLeft(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return rec.left + window.scrollX;
} //call it like findLeft('#header');
2) finde oben
function findTop(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return rec.top + window.scrollY;
} //call it like findTop('#header');
oder ) finde links und oben zusammen
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');
Sie könnten besser bedient werden, wenn Sie ein JavaScript-Framework verwenden, das über Funktionen verfügt, um solche Informationen (und vieles mehr!) Browserunabhängig zurückzugeben. Hier sind ein paar:
Mit diesen Frameworks können Sie Folgendes tun: $('id-of-img').top
, um die y-Pixel-Koordinate des Bildes abzurufen.
jQuery . offset () ruft die aktuellen Koordinaten des ersten Elements ab oder legt die Koordinaten jedes Elements in der Menge der übereinstimmenden Elemente relativ zum Dokument fest.
Ich habe die Antwort von @ meouw genommen, in clientLeft hinzugefügt, die den Rahmen zulässt, und dann drei Versionen erstellt:
getAbsoluteOffsetFromBody - Ähnlich wie bei @ meouw wird hiermit die absolute Position relativ zum Hauptteil oder HTML-Element des Dokuments abgerufen (abhängig vom Mackenmodus).
getAbsoluteOffsetFromGivenElement - gibt die absolute Position relativ zum angegebenen Element (relativeEl) zurück. Beachten Sie, dass das angegebene Element das Element el enthalten muss. Andernfalls verhält es sich wie getAbsoluteOffsetFromBody. Dies ist nützlich, wenn Sie zwei Elemente in einem anderen (bekannten) Element enthalten haben (optional mehrere Knoten in der Knotenstruktur) und diese an derselben Position platzieren möchten.
getAbsoluteOffsetFromRelative - gibt die absolute Position relativ zum ersten übergeordneten Element mit position: relative zurück. Dies ähnelt getAbsoluteOffsetFromGivenElement aus demselben Grund, reicht jedoch nur bis zum ersten übereinstimmenden Element.
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 };
}
Wenn Sie immer noch Probleme haben, insbesondere im Zusammenhang mit dem Scrollen, können Sie sich Folgendes ansehen: http://www.greywyvern.com/?post=331 - In getStyle ist mindestens ein fragwürdiger Code aufgefallen Das sollte in Ordnung sein, vorausgesetzt, die Browser verhalten sich, haben aber den Rest überhaupt nicht getestet.
wenn Sie jQuery verwenden, ist das Dimensions-Plugin exzellent und ermöglicht es Ihnen, genau das anzugeben, was Sie wollen.
z.B.
Relative Position, absolute Position, absolute Position ohne Polsterung, mit Polsterung ...
Es geht weiter, sagen wir einfach, man kann viel damit anfangen.
Der Vorteil der Verwendung von jQuery liegt in der geringen Dateigröße und der einfachen Verwendung. Sie können anschließend nicht mehr auf JavaScript zurückgreifen.
Wenn Sie jQuery verwenden, könnte dies eine einfache Lösung sein:
<script>
var el = $("#element");
var position = el.position();
console.log( "left: " + position.left + ", top: " + position.top );
</script>
Dies ist der beste Code, den ich erstellt habe (funktioniert im Gegensatz zu jQueries offset () auch in iframes). Das Webkit hat anscheinend ein etwas anderes Verhalten.
Basierend auf dem Kommentar von 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 };
}
Unterschied zwischen klein und klein
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 };
}
Schauen Sie sich die Koordinaten eines Beispiels an: http://javascript.info/tutorial/coordinates
Der sauberste Ansatz, den ich gefunden habe, ist eine vereinfachte Version der von jQueries offset
verwendeten Technik. Ähnlich wie bei einigen anderen Antworten beginnt es mit getBoundingClientRect
; Dann werden window
und documentElement
verwendet, um die Bildlaufposition anzupassen, sowie Dinge wie der Rand auf body
(häufig die Standardeinstellung).
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>
Ich habe es so gemacht, damit es mit alten Browsern kompatibel ist.
// 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;
}
Weitere Informationen zu Koordinaten in JavaScript finden Sie hier: http://javascript.info/tutorial/coordinates
Während dies bei so vielen Antworten sehr wahrscheinlich verloren gehen wird, funktionierten die Top-Lösungen hier nicht für mich.
Soweit ich das beurteilen konnte, hätte auch keine der anderen Antworten geholfen.
Lage:
In einer HTML5-Seite hatte ich ein Menü, das ein Navigationselement in einer Kopfzeile war (nicht DIE Kopfzeile, sondern eine Kopfzeile in einem anderen Element).
Ich wollte, dass die Navigation nach dem Scrollen oben bleibt, aber vorher war die Kopfzeile absolut positioniert (damit ich etwas anderes darüber legen konnte).
Die obigen Lösungen lösten niemals eine Änderung aus, da .offsetTop sich nicht ändern würde, da dies ein absolut positioniertes Element war. Zusätzlich war die .scrollTop-Eigenschaft einfach das oberste Element des obersten Elements ... das heißt 0 und würde immer 0 sein.
Alle Tests, die ich mit diesen beiden Ergebnissen durchgeführt habe (und dieselben mit getBoundingClientRect-Ergebnissen), sagten mir nicht, ob der obere Rand der Navigationsleiste jemals zum oberen Rand der sichtbaren Seite gescrollt wurde (wie in der Konsole angegeben, blieben sie einfach erhalten) die gleichen Nummern beim Scrollen aufgetreten sind).
Lösung
Die Lösung für mich war zu nutzen
window.visualViewport.pageTop
Der Wert der pageTop-Eigenschaft gibt den sichtbaren Bereich des Bildschirms wieder, sodass ich nachverfolgen kann, wo sich ein Element in Bezug auf die Grenzen des sichtbaren Bereichs befindet.
Es ist wahrscheinlich unnötig zu sagen, dass ich diese Lösung voraussichtlich verwenden werde, um programmgesteuert auf die Bewegung von Elementen zu reagieren, die gescrollt werden.
Ich hoffe, es hilft jemand anderem.
WICHTIGER HINWEIS: Dies scheint derzeit in Chrome und Opera zu funktionieren und definitiv nicht in Firefox (6-2018). ... bis Firefox VisualViewport unterstützt Ich empfehle, diese Methode NICHT zu verwenden (und ich hoffe, dass sie es bald tun ... es ist viel sinnvoller als der Rest).
UPDATE:
Nur ein Hinweis zu dieser Lösung.
Während ich immer noch finde, dass das, was ich entdeckt habe, sehr wertvoll für Situationen ist, in denen "... programmatisch auf die Bewegung von Elementen reagiert wird, die gescrollt werden". anwendbar. Die bessere Lösung für das Problem, das ich hatte, war die Verwendung von CSS, um Position: sticky für das Element festzulegen. Bei Verwendung von sticky kann ein Element ohne Verwendung von Javascript an der Spitze bleiben (HINWEIS: Es kann vorkommen, dass dies nicht so effektiv ist wie das Ändern des Elements auf fixed, aber für die meisten Verwendungszwecke ist der sticky-Ansatz wahrscheinlich besser).
UPDATE01:
Also wurde mir klar, dass ich für eine andere Seite eine Anforderung hatte, bei der ich die Position eines Elements in einer leicht komplexen Bildlaufkonfiguration ermitteln musste (Parallaxe plus Elemente, die als Teil einer Nachricht vorbeirollen). In diesem Szenario wurde mir klar, dass das Folgende den Wert angab, den ich verwendet habe, um zu bestimmen, wann etwas zu tun ist:
let bodyElement = document.getElementsByTagName('body')[0];
let elementToTrack = bodyElement.querySelector('.trackme');
trackedObjPos = elementToTrack.getBoundingClientRect().top;
if(trackedObjPos > 264)
{
bodyElement.style.cssText = '';
}
Hoffe, diese Antwort ist jetzt allgemein nützlicher.
Ich habe die Lösung von Andy E erfolgreich verwendet, um ein bootstrap 2-Modal zu positionieren, je nachdem, auf welchen Link in einer Tabellenzeile ein Benutzer klickt. Die Seite ist eine Tapestry 5-Seite und Javascript unten wird in die Seitenklasse Java importiert.
javascript:
function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset = elemRect.top - bodyRect.top;
offset = offset + 20;
$('#serviceLineModal').css("top", offset);
}
Mein Modalcode:
<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>
Der Link in der Schleife:
<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>
Und der Java Code in der Seitenklasse:
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');");
}
});
}
Hoffe das hilft jemandem, dieser Beitrag hat geholfen.
Um den Gesamtversatz eines Elements zu erhalten, können Sie alle übergeordneten Versätze rekursiv zusammenfassen:
function getParentOffsets(el): number {
if (el.offsetParent) {
return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
return 0;
}
}
mit dieser Utility-Funktion beträgt der gesamte obere Versatz eines dom-Elements:
el.offsetTop + getParentOffsets(el);
Nach langem Suchen und Testen scheint dies zu funktionieren
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 };
}
Ich dachte nur, ich würde das auch rausschmeißen.
Ich konnte es in älteren Browsern nicht testen, aber es funktioniert in der neuesten Version der Top 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()};
};
Holen Sie sich die Position des Div in Bezug auf links und oben
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
Da verschiedene Browser Rahmen, Abstände, Ränder usw. auf unterschiedliche Weise rendern. Ich habe eine kleine Funktion geschrieben, um die oberen und linken Positionen eines bestimmten Elements in jedem gewünschten Stammelement in präziser Dimension abzurufen:
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
Zum Abrufen der linken Position müssen Sie Folgendes zurückgeben:
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;
}
Danke ThinkingStiff für die Antwort , dies ist nur eine andere Version davon.