Jak uzyskać najwyższą pozycję elementu względem widocznego obszaru przeglądarki?

173

Chcę uzyskać pozycję elementu względem rzutni przeglądarki (rzutnia, w którym wyświetlana jest strona, a nie cała strona). Jak można to zrobić w JavaScript?

Wielkie dzięki

Waleed Eissa
źródło
2
Myślę, że to pytanie jest podobne do stackoverflow.com/questions/211703/…, które ma naprawdę fajne rozwiązanie.
Jakob Runge
1
@JakobRunge, To było „miłe” w 2013 roku?
Iulian Onofrei,
1
Rozważ przyjęcie rozwiązania.
Iulian Onofrei,

Odpowiedzi:

305

Istniejące odpowiedzi są teraz nieaktualne. Metoda rodzima getBoundingClientRect()istnieje już od jakiegoś czasu i robi dokładnie to, o co chodzi w pytaniu. Dodatkowo jest obsługiwany we wszystkich przeglądarkach (w tym IE 5, jak się wydaje!)

Ze strony MDN :

Zwracana wartość jest obiektem TextRectangle, który zawiera właściwości tylko do odczytu left, top, right i bottom opisujące ramkę (w pikselach), z lewym górnym względem lewego górnego obszaru widoku .

Używasz tego w ten sposób:

var viewportOffset = el.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var top = viewportOffset.top;
var left = viewportOffset.left;
Himanshu P
źródło
3
Może to nie działać poprawnie podczas korzystania z powiększenia przeglądarki (Android Chrome). Rozwiązanie z @rism ( patrz poniżej ) działa w tym przypadku
Dmitry
4
Dobre w większości przypadków, ale zakłada się, że element nie znajduje się wewnątrz osadzonej ramki iframe, prawda? Pytanie dotyczy względnego okna przeglądarki. El.getBoundingClientRect () zwróci względne okno iframe, a nie okno przeglądarki.
cakidnyc
6
Pytanie dotyczy względnego okna przeglądarki.
Dmitry Dvornikov
2
@Denilson getBoundingClientRect().topnie ma w moim IE11, zwraca 0. Masz jakieś rozwiązanie.
Arif
@Arif: Przepraszamy, ale nie mogę odtworzyć Twojego problemu. Przetestowałem to na IE11 i nadal otrzymałem wyniki: codepen.io/denilsonsa/pen/ypqyXj
Denilson Sá Maia
57

W moim przypadku, dla pewności co do przewijania, do równania dodałem okno window.scroll:

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

To pozwala mi uzyskać rzeczywistą względną pozycję elementu w dokumencie, nawet jeśli został przewinięty.

Fabio Nolasco
źródło
2
Czy nie powinieneś dodawać pozycji przewijania zamiast ją odejmować?
Iulian Onofrei,
Głosowałem za odpowiedzią, ale wciąż @lulian Onofrei ma rację. Proszę edytować.
pmrotule
@Fabio getBoundingClientRect().topnie ma w moim IE11, zwraca 0. Masz jakieś rozwiązanie.
Arif
1
@Arif window.scrollY || window.pageYOffsetmoże poprawić wsparcie
Fabian von Ellerts
@FabianvonEllerts :)
Arif
15

Edycja: Dodaj kod do konta do przewijania strony.

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);
    }
}

Argument id to identyfikator elementu, którego offset chcesz. Zaczerpnięte z dziwacznego postu .

Derek Swingley
źródło
1
Dziękuję za odpowiedź, ale myślę, że źle zrozumiałeś moje pytanie, wiem, jak uzyskać górę elementu względem strony, to, co próbuję zrobić, to uzyskać pozycję względem „okna przeglądarki” (tj. Okna przeglądarki , a nie dokument)
Waleed Eissa
Przepraszam, zrzuciło mnie twoje użycie 'viewport'. Więc mówisz, że chcesz uwzględnić chrome przeglądarki, tj. Pasek zakładek, pasek adresu itp.?
Derek Swingley
Nie, tylko okno, przez które widzisz stronę. Jeśli strona jest przewijana, będzie inna niż górna strona dokumentu, w przeciwnym razie będą takie same.
Waleed Eissa
Ok, rozumiem. Nie wiem, jak to zrobić ... zmieni odpowiedź, jeśli coś wymyślę.
Derek Swingley
Zrobiłem powyższy kod trochę brzydszy, ale działa ... użyj 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
źródło
Wydaje się, że jest to obliczane na podstawie górnej części dokumentu, a nie widoku
Scott Leonard
6

Możesz spróbować:

node.offsetTop - window.scrollY

Działa w przeglądarce Opera ze zdefiniowanym metatagiem viewport.

Szere Dyeri
źródło
7
Jeśli dobrze rozumiem dokumentację , offsetTopto jest względem najbliższego pozycjonowanego elementu. Który, w zależności od struktury strony, może być elementem głównym lub nie.
Denilson Sá Maia
5

jQuery implementuje to dość elegancko. Jeśli spojrzysz na źródło jQuery offset, zauważysz, że jest w zasadzie tak zaimplementowany:

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

return {
    top: rect.top + win.pageYOffset,
    left: rect.left + win.pageXOffset
};
jordancooperman
źródło
2

Funkcja na tej stronie zwróci prostokąt z górną, lewą, współrzędnymi wysokości i szerokości przekazanego elementu względem portu widoku przeglądarki.

    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;
}
ryzm
źródło
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;
}

źródło

karlsebal
źródło
1

Dzięki za wszystkie odpowiedzi. Wygląda na to, że Prototype ma już funkcję, która to robi (funkcja page ()). Przeglądając kod źródłowy funkcji stwierdziłem, że najpierw oblicza on przesunięcie elementu względem strony (tj. Do góry dokumentu), a następnie odejmuje od tego scrollTop. Więcej szczegółów w kodzie źródłowym prototypu.

Waleed Eissa
źródło
Dobra decyzja. Prawdopodobnie najlepiej jest wybrać jedną z głównych bibliotek, ponieważ jest bardziej prawdopodobne, że dadzą ten sam wynik w różnych przeglądarkach. Jeśli jesteś ciekawy, sprawdź moją odpowiedź. Kod tam zrobi, ale nie mam pojęcia, jak będzie działać w różnych przeglądarkach.
Derek Swingley
1

Zakładam, że na btn1stronie internetowej istnieje element o identyfikatorze , a także, że zawiera jQuery. Działa to we wszystkich nowoczesnych przeglądarkach Chrome, FireFox, IE> = 9 i Edge. jQuery jest używany tylko do określenia pozycji względem dokumentu.

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
źródło
1
jQuery to JavaScript. Myślę, że miałeś na myśli „to nie jest w 100% waniliowy / czysty JS”.
Hungerstar
Tak, o to mi chodziło.
Sunil
1

Czasami getBoundingClientRect()wartość właściwości obiektu pokazuje 0 dla IE. W takim przypadku musisz ustawićdisplay = 'block' dla elementu. Możesz użyć poniższego kodu dla wszystkich przeglądarek, aby uzyskać przesunięcie.

Rozszerz funkcjonalność jQuery:

(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));

Posługiwać się :

var elementOffset = $("#" + elementId).weOffset();
Arif
źródło