Rufen Sie die Position (X, Y) eines HTML-Elements relativ zum Browserfenster ab

1568

Ich möchte wissen, wie die X- und Y-Position von HTML-Elementen wie imgund divin JavaScript relativ zum Browserfenster ermittelt wird.

Jack
quelle
134
Relativ zu was?
AnthonyWJones
4
Ich hatte diese 7 Codezeilen verwendet, die in allen Browsern mit Diskrepanzen in ie5,6,7 funktionieren (ich erinnerte mich nicht an ein Proboem ... könnte der Dokumenttyp sein) ... quirksmode.org/js/findpos. html und ich haben es seit so vielen Jahren oft benutzt. Vielleicht kann jemand auf die Fehler hinweisen, wenn überhaupt.
Jayapal Chandran
98
@AnthonyWJones, ich nehme an, Sie brauchten das pedantische Vergnügen, aber es ist offensichtlich, wie immer, wenn es nicht spezifiziert ist, dass sich das OP auf den allgemeinsten Fall oder auf die Fensterkoordinaten des Browsers bezieht.
Motes
7
@Mote, Nein, das ist nicht so offensichtlich. Lassen Sie Folgerungen, Subjektivität und falsche Axiome beiseite. Es kann relativ zum Ansichtsfenster oder zum Seitenanfang sein (auch bekannt als document.documentElement).
Andre Figueiredo
15
Die Standardeinstellung ist nicht die Folgerung, sondern die logische Folge, sodass sie relativ zum Fenster ist, oder "Seitenanfang" könnte der Begriff sein, wie Sie es ausdrücken. In der Spieltheorie wird es als ein Konzept kodifiziert, das als Schelling-Punkt bezeichnet wird. Stellen Sie sicher, dass Sie angeben, wann Sie nicht den allgemeinsten Fall meinen.
Motes

Antworten:

1795

Der richtige Ansatz ist element.getBoundingClientRect():

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

Internet Explorer hat dies unterstützt, solange Sie sich wahrscheinlich darum kümmern, und es wurde schließlich in CSSOM-Ansichten standardisiert . Alle anderen Browser haben es vor langer Zeit übernommen .

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 Revisionen dieser Antwort auf eine optimierte, sich verschlechternde Implementierung.

Die von zurückgegebenen Werte element.getBoundingClientRect()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>');
Andy E.
quelle
143
Ein sehr interessanter Artikel über JS-Koordinaten . Dieser Artikel wird nirgends auf SO erwähnt, es sollte ..
e2-e4
6
Funktioniert nicht ... es sind 8 Pixel vertikal und horizontal, aufgrund des 8px-Randes im Körper. Meouws Lösung funktioniert perfekt. Wenn Sie möchten, habe ich einen kleinen Test, um das Problem zu demonstrieren.
CpnCrunch
3
Eigentlich denke ich, es kommt darauf an, wovon du eigentlich die Koordinaten bekommen willst. Die Frage ist etwas mehrdeutig. Ihre Antwort ist richtig, wenn Sie nur die Koordinaten relativ zum Ansichtsfenster oder relativ zum Körperelement wollen, aber das hilft Ihnen nicht, wenn Sie die absolute Position des Elements wollen (was meiner Meinung nach die meisten Leute wollen). . Die Antwort von meouw gibt Ihnen das auch nicht, es sei denn, Sie entfernen die Bits '-scrollLeft' und '-scrollTop'.
CpnCrunch
4
@CpnCrunch: Ich verstehe, was du jetzt meinst; Ich wusste nicht, dass Sie sich auf den letzten Teil meiner Antwort beziehen. Wenn der Körper einen Rand hat, wird sein Begrenzungsrahmen auf jeder Seite um diese Anzahl von Pixeln versetzt. In diesem Fall müssten Sie auch den berechneten Randstil von den Körperkoordinaten subtrahieren. Es ist jedoch erwähnenswert, dass CSS-Resets den Rand entfernen <body>.
Andy E
3
element.getBoundingClientRect().topGibt bei einem position: fixedElement in iOS (iPhone 8) keinen korrekten oberen Versatz zurück, wenn es ein fokussiertes Eingabeelement enthält und die virtuelle Tastatur nach oben gerutscht ist. Wenn der tatsächliche Versatz von der Oberseite des Fensters beispielsweise 200 Pixel beträgt, wird er als 420 Pixel gemeldet, wobei 220 Pixel die Höhe der virtuellen Tastatur ist. Wenn Sie Elemente festlegen position: absoluteund an derselben Position wie fest positionieren, erhalten Sie die richtigen 200 Pixel. Ich kenne keine Lösung dafür.
Jānis Elmeris
327

Die Bibliotheken gehen einige Längen, um genaue Offsets für ein Element zu erhalten.
Hier ist eine einfache Funktion, die die Arbeit unter allen Umständen erledigt, die ich versucht 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; 
meouw
quelle
14
ändere: el = el.parentNode in: el = el.offsetParent; und es scheint jetzt für verschachtelte Iframes zu funktionieren ... Ich denke, das haben Sie beabsichtigt?
Adam
4
Diese Lösung ist unvollständig. Versuchen Sie, einen Div mit einem dicken Rand zu versehen und nisten Sie ihn einige Male. In jeder Version von Firefox (2-5) wird es um die Randbreite (n) versetzt (auch im Modus zur Einhaltung von Standards).
ck_
3
Gibt es dafür keinen saubereren Weg, wie eine el.totalOffsetLeft- und eine totalOffsetTop-Funktion? jQuery hat sicherlich diese Option, aber es ist eine Schande, dass es dafür keine offizielle Methode gibt. Müssen wir auf DOM4 warten? Ich erstelle eine HTML5-Canvas-Anwendung, daher denke ich, dass die beste Lösung darin besteht, Canvas-Elemente in einen Iframe einzufügen, damit ich echte Koordinaten mit clientX und clientY erhalten kann, wenn wir auf element klicken.
Taufe
1
Also, @Adam und meouw, sagen Sie, dass der erste Codeblock falsch ist? Warum dann nicht das ganz entfernen? (Diese Frage hat im Laufe der Jahre einige Zuschauer gesehen; könnte es schön sein, Dinge zu entfernen, wenn sie falsch sind?)
Arjan
2
@baptx: Ich weiß, dass dies eine späte Antwort ist, aber ich habe Ihren Kommentar nicht früher gesehen. In meiner Antwort unten finden Sie eine standardkonformere Alternative. Sie benötigen den Fallback-Code nicht einmal wirklich, da ihn die Browser seit langem unterstützen.
Andy E
242

Dies hat bei mir funktioniert (geändert von der Antwort mit der höchsten Stimme):

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
Adam Grant
quelle
1
Nur diese Lösung funktioniert für mich, wenn ein Element platziert wird, in divdessen Mitte CSS zentriert ist top:50%, left:50%; transform:translate(-50%, -50%);... ausgezeichnet. Stimmen Sie der @ ScottBiggs-Frage zu. Logisch ist es, nach Einfachheit zu suchen.
Nelek
3
Vielleicht ist es kein Gewinner, weil es das gleiche wie die Lösung von Andy E ist, aber es funktioniert nicht in alten Browsern <IE9
Niltoid
getBoundingClientRect verursacht einen massiven Repaint-Spike in meinen Performance-Charts
Frumbert
1
Sie sollten definieren rectverwenden var, letoder const. Ansonsten ist es definiert als window.rect.
Hev1
2
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)wird die mittlere Position eines Elements zurückgeben
abhishake
97

Wenn Sie es nur in Javascript getan wollen , sind hier einige Einzeiler mitgetBoundingClientRect()

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

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

Die erste Zeile gibt offsetTopY relativ zum Dokument zurück. Die zweite Zeile gibt beispielsweise offsetLeftX relativ zum Dokument zurück.

getBoundingClientRect() ist eine Javascript-Funktion, die die Position des Elements relativ zum Ansichtsfenster des Fensters zurückgibt.

Mustkeem K.
quelle
2
Dies sollte die Lösung sein. Es gibt hier keinen langen Code bs, es ist verständlich und sehr genau!
E Alexis MT
2
Was ist, wenn sich das Element in einem scrollbaren Element befindet? Die einzige Möglichkeit, dies zu tun, besteht darin, offsetTop aller übergeordneten Elemente zu summieren, wie andere Antworten vermuten lassen
Dmitri Pisarev,
Wie Dmitri feststellt, ist dies falsch und sehr fehlerhaft. Es sollte nicht so viele Stimmen haben wie es ist. Es befindet sich IMMER auch in einem scrollbaren Element, da das Dokument selbst gescrollt werden kann. Mit anderen Worten, es sei denn, das gesamte Dokument passt in das Ansichtsfenster, ist es immer falsch, wenn der Benutzer überhaupt durch das Hauptfenster gescrollt hat.
Lev
46

HTML-Elemente in den meisten Browsern haben: -

offsetLeft
offsetTop

Diese geben die Position des Elements relativ zu seinem 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 weniger verbreitet. Sie geben eine Elementposition mit dem übergeordneten Clientbereich an (der aufgefüllte Bereich ist Teil des Clientbereichs, Rand und Rand jedoch nicht).

AnthonyWJones
quelle
36

Wenn die Seite mindestens "DIV" enthält, wirft die von meouw angegebene Funktion den Wert "Y" über die aktuellen Seitengrenzen hinaus. Um die genaue Position zu finden, müssen Sie sowohl offsetParent's als auch parentNode's verarbeiten.

Probieren Sie den folgenden 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];
};
Refik Ayata
quelle
1
Wie bei den anderen Lösungen funktioniert auch bei FF 24.4 der obige Code nicht, wenn Randbreiten als Teil des Positionierungslayouts vorhanden sind.
Rob
Du bist ein Lebensretter. Ich arbeite gerade an einigen ziemlich tiefen GWT-Fehlern und das Einfügen in eine JSNI-Methode löst alle meine Probleme !!
Will Byrne
35

Sie können zwei Eigenschaften hinzufügen Element.prototype, um den oberen / linken Rand eines Elements abzurufen.

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 Ergebnisse zu jQuery zu vergleichen offset().topund .left: http://jsfiddle.net/ThinkingStiff/3G7EZ/

ThinkingStiff
quelle
14
Änderungen werden Element.prototypeim Allgemeinen als schlechte Idee angesehen . Es ist sehr schwierig, Code zu pflegen. Dieser Code berücksichtigt auch nicht das Scrollen.
Jared Forsyth
23

So rufen Sie die Position relativ zur Seite effizient und ohne Verwendung einer rekursiven Funktion ab: (einschließlich 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;
Abdul Rahim Haddad
quelle
Durch das Einfügen aller wichtigen scrollTop / scrollLeft wird diese Antwort etwas korrekter.
Scunliffe
19

Wie wäre es mit so etwas, indem wir die ID des Elements übergeben und es links oder oben zurückgibt, können wir sie auch kombinieren:

1) links finden

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 3) links und oben zusammen finden

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');
Alireza
quelle
16

Möglicherweise ist es besser, ein JavaScript-Framework zu verwenden, das über Funktionen verfügt, mit denen solche Informationen (und vieles mehr!) Browserunabhängig zurückgegeben werden können. Hier sind ein paar:

Mit diesen Frameworks können Sie Folgendes tun: $('id-of-img').top die y-Pixel-Koordinate des Bildes ermitteln.

Shalom Craimer
quelle
2
@Costa Sie alle verwenden diese Art von Funktionen, obwohl dies ein sich entwickelndes Feld ist, da verschiedene Browser unterschiedlich der Spezifikation entsprechen. So viel im Code befasst sich mit dem "Reparieren" von Dingen, die schief gehen. Sie sollten sich wirklich den Quellcode ansehen.
Shalom Craimer
18
@scraimer: jQuery und YUI sind KEINE Frameworks !!! Das sind Bibliotheken ! Es ist nicht das gleiche. Unter Berufung auf jquery.com : "jQuery ist eine schnelle, kleine und funktionsreiche JavaScript- Bibliothek ." Unter Berufung auf yuilibrary.com (Sie können das "Zauberwort" auch in der URL sehen ...): "YUI ist eine kostenlose Open-Source-JavaScript- und CSS- Bibliothek zum Erstellen von interaktiven Webanwendungen."
Sk8erPeter
29
Sie sollten also nur für diese einfache Aufgabe riesige Bibliotheken verwenden? Nicht nötig. Ich hasse es, dass ich jedes Mal, wenn ich etwas mit js machen möchte, diese jQuery-Lösungen bekomme. jQuery ist nicht JS!
Opptatt Jobber
1
@OpptattJobber Ich stimme zu ... JQuery ist kein Javascript. Es basiert auf Javascript, ist aber eine ganz andere Programmiersprache.
Nick Manning
5
@NickManning Es ist keine neue Sprache, sondern eine Abstraktionsschicht für das DOM, bei der Kompatibilitäts- und Leistungsumgehungen nicht direkt in Ihren Code geschrieben werden müssen. Wenn Sie jQuery nicht verwenden, sollten Sie sowieso eine Art Abstraktionsschicht verwenden.
Ginman
15

jQuery .offset () ruft die aktuellen Koordinaten des ersten Elements ab oder legt die Koordinaten jedes Elements in der Gruppe der übereinstimmenden Elemente relativ zum Dokument fest.

Akauppi
quelle
Aus irgendeinem Grund werden im IE im Vergleich zu anderen Browsern nicht die gleichen Ergebnisse erzielt. Ich denke, dass es im IE eine Position relativ zum Fenster gibt. Wenn Sie also scrollen, erhalten Sie im IE andere Ergebnisse als in anderen
Abdul Rahim Haddad
1
offset () wird durch Zoom verwirrt, zumindest in Android Chrome, daher ist es nutzlos. stackoverflow.com/a/11396681/1691517 zeigt eine zoomtolerante Methode.
Timo Kähkönen
10

Ich habe die Antwort von @ meouw genommen, in der clientLeft hinzugefügt, die den Rand zulässt, und dann drei Versionen erstellt:

getAbsoluteOffsetFromBody - Ähnlich wie bei @ meouw wird hier 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 genauso wie getAbsoluteOffsetFromBody. Dies ist nützlich, wenn zwei Elemente in einem anderen (bekannten) Element enthalten sind (optional mehrere Knoten im Knotenbaum) und diese an derselben Position positionieren möchten.

getAbsoluteOffsetFromRelative - Gibt die absolute Position relativ zum ersten übergeordneten Element mit position: relative zurück. Dies ähnelt getAbsoluteOffsetFromGivenElement aus demselben Grund, geht 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 beim Scrollen, können Sie sich http://www.greywyvern.com/?post=331 ansehen. Ich habe mindestens einen fragwürdigen Code in getStyle bemerkt, der in Ordnung sein sollte, vorausgesetzt, die Browser verhalten sich , aber den Rest habe ich überhaupt nicht getestet.

James Carlyle-Clarke
quelle
Interessant ... aber auf Edge gibt getAbsoluteOffsetFromBody (Element) .top beim Scrollen einen anderen Wert zurück, in Chrome bleibt er beim Scrollen konsistent. Es scheint, dass Edge sich mit der Bildlaufposition anpasst. Wenn das Element aus der Ansicht gescrollt wird, erhalte ich einen negativen Wert.
Norman
getAbsoluteOffsetFromRelative machte meinen Tag, ich musste Bootstrap-Tooltip ohne Javascript von Bootstrap reproduzieren, es hat mir sehr geholfen.
Nolyurn
Nur für den Fall, dass Meouw seinen Benutzernamen ändert, Link zur Antwort: stackoverflow.com/a/442474/3654837 . (Ich möchte diesen alten Thread nicht stoßen, also ja, ich habe einen Kommentar abgegeben)
Mukyuu
8

Wenn Sie jQuery verwenden, das Dimensions-Plugin hervorragend und ermöglicht es Ihnen, genau anzugeben, was Sie möchten.

z.B

Relative Position, absolute Position, absolute Position ohne Polsterung, mit Polsterung ...

Es geht weiter, sagen wir einfach, Sie können viel damit anfangen.

Der Vorteil der Verwendung von jQuery ist außerdem die geringe Dateigröße und die einfache Verwendung. Ohne jQuery können Sie danach nicht mehr auf JavaScript zurückgreifen.

John_
quelle
8

Dies ist der beste Code, den ich erstellt habe (funktioniert auch in iframes, im Gegensatz zu jQuerys offset ()). Das Webkit scheint sich etwas anders zu verhalten.

Basierend auf meouws Kommentar:

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 };
}
Ron Reiter
quelle
Beachten Sie, dass Sie benötigen jQueryzu verwenden $.browser.webkit; Sie müssen herumspielen, um navigator.userAgentdasselbe mit pure zu tun JavaScript.
SP
2
$ .browser ist nicht mehr verfügbar in der neuesten Version von jQuery
Gus
Leider funktioniert der obige Code auch mit FF 24.4 nicht, wenn Randbreiten als Teil des Positionierungslayouts vorhanden sind.
Rob
8

Wenn Sie jQuery verwenden, kann dies eine einfache Lösung sein:

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

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 ein Beispiel für Koordinaten an: http://javascript.info/tutorial/coordinates

KingRider
quelle
Dies funktioniert leider nicht für alle Elemente, die in einem modernen HTML-Dokument enthalten sind. Embedded - <svg>Elemente, zum Beispiel, haben nicht offsetLeft, offsetTopund offsetParentEigenschaften.
Jonathan Eunice
Es ist gerecht DIVoder IMGnicht SVG. "Beispielkoordinaten anzeigen"? Sie können das Objekt svg als Positionsaufruf getOffsetRect finden. Versuchen Sie, die Objektarbeit abhängig zu machen.
KingRider
7

Der sauberste Ansatz, den ich gefunden habe, ist eine vereinfachte Version der von jQuery's verwendeten Technik offset. Ähnlich wie bei einigen anderen Antworten beginnt es mit getBoundingClientRect; Es verwendet dann das windowund das documentElement, um die Bildlaufposition sowie Dinge wie den Rand auf dem body(oft die Standardeinstellung) anzupassen .

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

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

James Montagne
quelle
6

Während dies bei so vielen Antworten sehr wahrscheinlich verloren geht, haben die Top-Lösungen hier bei mir nicht funktioniert.
Soweit ich das beurteilen konnte, hätte keine der anderen Antworten geholfen.

Situation :
Auf einer HTML5-Seite hatte ich ein Menü, das ein Navigationselement in einem Header war (nicht DER Header, sondern ein Header in einem anderen Element).
Ich wollte, dass die Navigation oben bleibt, sobald ein Benutzer zu ihr gescrollt hat, aber zuvor war die Kopfzeile absolut positioniert (damit ich sie etwas anderes leicht überlagern kann).
Die oben genannten Lösungen haben nie eine Änderung ausgelöst, da sich .offsetTop nicht ändern würde, da dies ein absolut positioniertes Element war. Zusätzlich war die .scrollTop-Eigenschaft einfach die Spitze des obersten Elements ... das heißt 0 und wäre immer 0.
Alle Tests, die ich mit diesen beiden durchgeführt habe (und die gleichen mit den Ergebnissen von getBoundingClientRect), haben mir nicht gesagt, ob der obere Rand der Navigationsleiste jemals zum oberen Rand der sichtbaren Seite gescrollt hat (wie in der Konsole angegeben, blieben sie beim Scrollen einfach die gleichen Zahlen aufgetreten).

Lösung
Die Lösung für mich war die Verwendung

window.visualViewport.pageTop

Der Wert der pageTop-Eigenschaft spiegelt den sichtbaren Bereich des Bildschirms wider, sodass ich verfolgen 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 jedes Mal verwenden werde, wenn ich mich mit dem Scrollen beschäftige, um programmgesteuert auf die Bewegung von Elementen zu reagieren, die gescrollt werden.
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 macht 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 "... programmgesteuert auf Bewegungen von Elementen reagiert wird, die gescrollt werden". anwendbar. Die bessere Lösung für das Problem, das ich hatte, war die Verwendung von CSS zum Einstellen Position: klebrigauf dem Element. Wenn Sie Sticky verwenden, kann ein Element ohne Verwendung von Javascript oben bleiben (

HINWEIS: Manchmal funktioniert dies nicht so effektiv wie das Ändern des Elements in "Fixed", aber für die meisten Anwendungen ist der Sticky-Ansatz wahrscheinlich überlegen.) UPDATE01:
Also habe ich das erkannt Für eine andere Seite hatte ich eine Anforderung, bei der ich die Position eines Elements in einem leicht komplexen Bildlauf-Setup ermitteln musste (Parallaxe plus Elemente, die als Teil einer Nachricht vorbeirollen). In diesem Szenario wurde mir klar, dass das Folgende den Wert lieferte, den ich verwendete, 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 allgemeiner nützlich.

MER
quelle
Dies ist sehr wahrscheinlich ganz oben auf so vielen Antworten, wenn Sie auf Aktiv klicken , um die Antworten zu sortieren
lucchi
@lucchi: D Nun, ich nehme an, ich könnte den Text @ oben entfernen ... obwohl ich gerade wieder in diesem Fall vorgekommen bin und festgestellt habe, dass ich eine bessere Lösung für mein eigenes Problem gefunden habe ... obwohl meine Antwort eher eine ist Fußnote zu den vollständigeren Antworten. Ich vermute, meine Anforderungen waren vielleicht nicht so häufig, dass die anderen Antworten bei mir nicht funktionierten?
MER
1
Ich schätze Ihre Antwort trotzdem, es war nur, um Ihnen zu sagen, dass jeder, der will, weiß, dass Sie etwas Neues geschrieben haben. Sie sind nicht allein ....
Lucchi
5

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

Bojan Kseneman
quelle
4

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 Dienstprogrammfunktion beträgt der gesamte obere Versatz eines dom-Elements:

el.offsetTop + getParentOffsets(el);
Kevin K.
quelle
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;
}

Vielen Dank an ThinkingStiff für die Antwort , dies ist nur eine andere Version davon.

Văn Quyết
quelle
2

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 das unten stehende Javascript wird in die Java-Seitenklasse 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.

Mark Espinoza
quelle
Dieser JS-Code hat mir geholfen. Ich habe eine alte Webforms-App mit mehreren Platzhaltern, in die ASPX-Seiten eingefügt wurden, und ich konnte nicht herausfinden, wie ichChild () eines Popup-Felds anhängen kann, das ich erstellt habe, um es in das Ansichtsfenster zu bringen, da der gesamte DOM-Baum fehlerhaft ist mit den mehreren Platzhaltern und falschem Markup. Die Verwendung von body.getBoundingClientRect () und die Verwendung der Oberseite bei der Positionierung war das, was ich brauchte. Vielen Dank.
Brad Martin
1

Nach vielen Recherchen und Tests 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 };
}

Siehe http://jsbin.com/xuvovalifo/edit?html,js,output

Kernowcode
quelle
1

Ich dachte nur, ich würde das auch da rauswerfen.
Ich konnte es nicht in älteren Browsern testen, aber es funktioniert in den neuesten 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()};
};
Duncan
quelle
0

Da verschiedene Browser Rahmen, Auffüllungen, 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 einer genauen Dimension abzurufen:

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

Um die linke Position abzurufen, müssen Sie Folgendes zurückgeben:

    return offsetRect.left - rootRect.left;
Samadadi
quelle
-1

Holen Sie sich die Position von 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 
Vishal
quelle
Ich habe nach unten gestimmt, weil unten und rechts keine Eigenschaften von offset () sind
MacroMan
@ MacroMan, ich respektiere Ihre Entscheidung, aber ich habe bereits im Text erklärt, dass "unten und rechts der Code nicht getestet wird". Außerdem werde ich meinen Code sehr bald aktualisieren.
Vishal
Ich denke, es ist el.offsetTopund el.offsetLeft(das OP sagt nichts über jQuery ... Ich bin nicht sicher, warum Ihre Antwort auch jQuery verwendet ...)
Mesqueeb