Wie erhalte ich die oberste Position eines Elements relativ zum Ansichtsfenster des Browsers?

173

Ich möchte die Position eines Elements relativ zum Ansichtsfenster des Browsers ermitteln (das Ansichtsfenster, in dem die Seite angezeigt wird, nicht die gesamte Seite). Wie geht das in JavaScript?

Danke vielmals

Waleed Eissa
quelle
2
Ich denke, diese Frage ähnelt der von stackoverflow.com/questions/211703/…, die eine wirklich gute Lösung bietet.
Jakob Runge
1
@JakobRunge, das war 2013 "schön"?
Iulian Onofrei
1
Erwägen Sie, eine Lösung zu akzeptieren.
Iulian Onofrei

Antworten:

305

Die vorhandenen Antworten sind jetzt veraltet. Die native getBoundingClientRect()Methode gibt es schon eine ganze Weile und macht genau das, was die Frage verlangt. Außerdem wird es in allen Browsern unterstützt (einschließlich IE 5, wie es scheint!).

Von der MDN-Seite :

Der zurückgegebene Wert ist ein TextRectangle-Objekt, das schreibgeschützte Eigenschaften für links, oben, rechts und unten enthält, die das Rahmenfeld in Pixel beschreiben, wobei sich das obere linke relativ zum oberen linken Rand des Ansichtsfensters befindet .

Du benutzt es so:

var viewportOffset = el.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var top = viewportOffset.top;
var left = viewportOffset.left;
Himanshu P.
quelle
3
Dies funktioniert möglicherweise nicht richtig, wenn Sie den Browser-Zoom (Android Chrome) verwenden. Lösung von @rism ( siehe unten ) funktioniert in diesem Fall
Dmitry
4
Gut für die meisten Fälle, aber es wird davon ausgegangen, dass sich das Element nicht in einem eingebetteten Iframe befindet, oder? Die Frage bezieht sich auf das Fenster des Browsers. Das el.getBoundingClientRect () gibt relativ das Fenster des Iframes zurück, nicht das Browserfenster.
Cakidnyc
6
Die Frage bezieht sich auf das Fenster des Browsers.
Dmitry Dvornikov
2
@Denilson getBoundingClientRect().topist nicht in meinem IE11, es gibt 0 zurück. Haben Sie eine Lösung.
Arif
@Arif: Entschuldigung, aber ich kann Ihr Problem nicht reproduzieren. Ich habe dies auf IE11 getestet und immer noch Ergebnisse erhalten: codepen.io/denilsonsa/pen/ypqyXj
Denilson Sá Maia
57

In meinem Fall habe ich, um beim Scrollen sicher zu sein, die window.scroll zur Gleichung hinzugefügt:

var element = document.getElementById('myElement');
var topPos = element.getBoundingClientRect().top + window.scrollY;
var leftPos = element.getBoundingClientRect().left + window.scrollX;

Dadurch kann ich die tatsächliche relative Position des Elements im Dokument ermitteln, auch wenn es gescrollt wurde.

Fabio Nolasco
quelle
2
Solltest du nicht die Bildlaufposition hinzufügen, anstatt sie zu subtrahieren?
Iulian Onofrei
Ich habe die Antwort positiv bewertet, aber trotzdem hat @lulian Onofrei recht. Bitte bearbeiten.
pmrotule
@Fabio getBoundingClientRect().topist nicht in meinem IE11, es gibt 0 zurück. Haben Sie eine Lösung.
Arif
1
@Arif window.scrollY || window.pageYOffsetkann die Unterstützung verbessern
Fabian von Ellerts
@ FabianvonEllerts :)
Arif
15

Bearbeiten: Fügen Sie Code hinzu, um das Scrollen der Seite zu berücksichtigen.

function findPos(id) {
    var node = document.getElementById(id);     
    var curtop = 0;
    var curtopscroll = 0;
    if (node.offsetParent) {
        do {
            curtop += node.offsetTop;
            curtopscroll += node.offsetParent ? node.offsetParent.scrollTop : 0;
        } while (node = node.offsetParent);

        alert(curtop - curtopscroll);
    }
}

Das Argument id ist die ID des Elements, dessen Versatz Sie möchten. Adaptiert von einem Quirksmode-Beitrag .

Derek Swingley
quelle
1
Vielen Dank für Ihre Antwort, aber ich glaube, Sie haben meine Frage falsch verstanden. Ich weiß, wie man den Anfang eines Elements relativ zur Seite erhält. Ich versuche, die Position relativ zum 'Ansichtsfenster' (dh zum Browserfenster) zu ermitteln , nicht das Dokument)
Waleed Eissa
Entschuldigung, Ihre Verwendung des Ansichtsfensters hat mich umgehauen. Sie sagen also, Sie möchten das Chrome des Browsers berücksichtigen, dh die Lesezeichen-Symbolleiste, die Positionsleiste usw.?
Derek Swingley
Nein, nur das Fenster, durch das Sie die Seite sehen. Wenn die Seite gescrollt wird, unterscheidet sich diese von der Dokumentoberseite, andernfalls sind sie gleich.
Waleed Eissa
Oh ok ich verstehe. Ich bin mir nicht sicher, wie ich das machen soll ... wird meine Antwort bearbeiten, wenn mir etwas einfällt.
Derek Swingley
Ich habe den Code oben etwas hässlicher gemacht, aber es funktioniert ... benutze offsetParent.scrollTop
Derek Swingley
10
var element =  document.querySelector('selector');
var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;
GURU PRASAD
quelle
Dies scheint vom oberen Rand des Dokuments zu berechnen, nicht vom Ansichtsfenster
Scott Leonard
6

Du kannst es versuchen:

node.offsetTop - window.scrollY

Es funktioniert unter Opera mit definiertem Viewport-Meta-Tag.

Szere Dyeri
quelle
7
Wenn ich die Dokumentation richtig verstehe , offsetTopbezieht sie sich auf das am nächsten positionierte Element. Was je nach Seitenstruktur ein Stammelement sein kann oder nicht.
Denilson Sá Maia
5

jQuery setzt dies recht elegant um. Wenn Sie sich die Quelle für jQuery's ansehen offset, werden Sie feststellen, dass dies im Grunde so implementiert ist:

var rect = elem.getBoundingClientRect();
var win = elem.ownerDocument.defaultView;

return {
    top: rect.top + win.pageYOffset,
    left: rect.left + win.pageXOffset
};
jordancooperman
quelle
2

Die Funktion auf dieser Seite gibt ein Rechteck mit den Koordinaten oben, links, Höhe und Breite eines übergebenen Elements relativ zum Browser-Ansichtsport zurück.

    localToGlobal: function( _el ) {
       var target = _el,
       target_width = target.offsetWidth,
       target_height = target.offsetHeight,
       target_left = target.offsetLeft,
       target_top = target.offsetTop,
       gleft = 0,
       gtop = 0,
       rect = {};

       var moonwalk = function( _parent ) {
        if (!!_parent) {
            gleft += _parent.offsetLeft;
            gtop += _parent.offsetTop;
            moonwalk( _parent.offsetParent );
        } else {
            return rect = {
            top: target.offsetTop + gtop,
            left: target.offsetLeft + gleft,
            bottom: (target.offsetTop + gtop) + target_height,
            right: (target.offsetLeft + gleft) + target_width
            };
        }
    };
        moonwalk( target.offsetParent );
        return rect;
}
Risma
quelle
2
function inViewport(element) {
    let bounds = element.getBoundingClientRect();
    let viewWidth = document.documentElement.clientWidth;
    let viewHeight = document.documentElement.clientHeight;

    if (bounds['left'] < 0) return false;
    if (bounds['top'] < 0) return false;
    if (bounds['right'] > viewWidth) return false;
    if (bounds['bottom'] > viewHeight) return false;

    return true;
}

Quelle

Karlsebal
quelle
1

Danke für alle Antworten. Es scheint, dass Prototype bereits eine Funktion hat, die dies ausführt (die Funktion page ()). Beim Anzeigen des Quellcodes der Funktion stellte ich fest, dass zuerst die Elementversatzposition relativ zur Seite (dh zur Dokumentoberseite) berechnet und dann das scrollTop davon subtrahiert wird. Weitere Informationen finden Sie im Quellcode des Prototyps.

Waleed Eissa
quelle
Gute Entscheidung. Es ist wahrscheinlich am besten, mit einer der Hauptbibliotheken zu arbeiten, da diese mit größerer Wahrscheinlichkeit über alle Browser hinweg das gleiche Ergebnis liefern. Wenn Sie neugierig sind, überprüfen Sie meine meine Antwort. Der Code dort wird dies tun, aber ich habe keine Ahnung, wie er sich über alle Browser hinweg halten wird.
Derek Swingley
1

Ich gehe davon aus, dass ein Element mit der ID von btn1auf der Webseite vorhanden ist und dass jQuery enthalten ist. Dies hat in allen modernen Browsern von Chrome, FireFox, IE> = 9 und Edge funktioniert. jQuery wird nur verwendet, um die Position relativ zum Dokument zu bestimmen.

var screenRelativeTop =  $("#btn1").offset().top - (window.scrollY || 
                                            window.pageYOffset || document.body.scrollTop);

var screenRelativeLeft =  $("#btn1").offset().left - (window.scrollX ||
                                           window.pageXOffset || document.body.scrollLeft);
Sunil
quelle
1
jQuery ist JavaScript. Ich glaube, Sie meinten "es ist nicht 100% Vanille / reines JS."
Hungerstar
Ja das meinte ich.
Sunil
1

Manchmal getBoundingClientRect()zeigt der Eigenschaftswert des Objekts 0 für IE. In diesem Fall müssen Sie display = 'block'für das Element festlegen . Sie können den folgenden Code für alle Browser verwenden, um den Offset zu erhalten.

Erweitern Sie die jQuery-Funktionalität:

(function($) {
    jQuery.fn.weOffset = function () {
        var de = document.documentElement;
        $(this).css("display", "block");
        var box = $(this).get(0).getBoundingClientRect();
        var top = box.top + window.pageYOffset - de.clientTop;
        var left = box.left + window.pageXOffset - de.clientLeft;
        return { top: top, left: left };
    };
}(jQuery));

Verwenden :

var elementOffset = $("#" + elementId).weOffset();
Arif
quelle