Як отримати верхнє положення елемента відносно вікна перегляду браузера?


173

Я хочу отримати позицію елемента відносно вікна перегляду браузера (вікно перегляду, в якому відображається сторінка, а не вся сторінка). Як це можна зробити в JavaScript?

Велике дякую


2
Я думаю, що це питання схоже на stackoverflow.com/questions/211703/…, який має дуже гарне рішення.
Якоб Рунге

1
@JakobRunge, Це було "приємно" у 2013 році?
Юліан Онофрей

1
Подумайте про прийняття рішення.
Юліан Онофрей

Відповіді:


305

Існуючі відповіді застаріли. Нативний getBoundingClientRect()метод існує вже досить довгий час, і він робить саме те, що запитання вимагає. Крім того, він підтримується у всіх браузерах (включаючи IE 5, здається!)

На сторінці MDN :

Повернене значення - це об'єкт TextRectangle, що містить властивості лише для читання зліва, вгорі, вправо і внизу, що описують вікно рамки, у пікселях, зверху ліворуч відносно верхнього лівого огляду області перегляду .

Ви використовуєте його так:

var viewportOffset = el.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var top = viewportOffset.top;
var left = viewportOffset.left;

3
Це може не працювати належним чином при використанні масштабування браузера (Android Chrome). Рішення від @rism ( див. Нижче ) працює в цій справі
Дмитро

4
Добре для більшості випадків, але передбачається, що елемент не знаходиться всередині вбудованої рамки кадрів, правда? Питання задається відносно вікна браузера. El.getBoundingClientRect () поверне відносно вікна iframe, а не вікна браузера.
cakidnyc

6
Питання задається відносно вікна браузера.
Дмитро Дворніков

2
@Denilson getBoundingClientRect().topне в моєму IE11, він повертається 0. У вас є рішення.
Аріф

@Arif: Вибачте, але я не можу відтворити вашу проблему. Я перевірив це на IE11 і все-таки отримав результати: codepen.io/denilsonsa/pen/ypqyXj
Denilson Sá Maia

57

У моєму випадку, щоб бути безпечним щодо прокрутки, я додав window.scroll до рівняння:

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

Це дозволяє мені отримати реальне відносне положення елемента на документі, навіть якщо він був прокручений.


2
Хіба ви не повинні додавати позицію прокрутки, а не віднімати її?
Юліан Онофрей

Я відповів на відповідь, але все-таки @lulian Onofrei має рацію. Відредагуйте.
pmrotule

@Fabio getBoundingClientRect().topне в моєму IE11, він повертається 0. У вас є рішення.
Аріф

1
@Arif window.scrollY || window.pageYOffsetможе покращити підтримку
Фабіан фон Еллертс

@FabianvonEllerts :)
Аріф

15

Редагувати: Додайте код для облікового запису для прокрутки сторінки.

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

Аргумент id - це ідентифікатор елемента, зміщення якого ви хочете. Адаптовано з допису на вигадку .


1
Дякую за вашу відповідь, але я думаю, що ви неправильно зрозуміли моє запитання, я знаю, як отримати верхню частину елемента відносно сторінки, що я намагаюся зробити, це отримати позицію відносно "вікна перегляду" (тобто вікна браузера , а не документ)
Waleed Eissa

Вибачте, що ваше використання "viewport" кинуло мене. Отже, ви кажете, що хочете обліковувати хром браузера, тобто панель інструментів закладок, панель розташування тощо?
Дерек Свінглі

Ні, просто вікно, через яке ви бачите сторінку. Якщо сторінка прокручується, це буде відрізнятися від верху документа, інакше вони однакові.
Waleed Eissa

Добре, я розумію. Не знаю, як це зробити ... відредагую свою відповідь, якщо я щось придумаю.
Дерек Свінглі

Я зробив код вище трохи потворнішим, але він працює ... використовуйте offsetParent.scrollTop
Дерек

10
var element =  document.querySelector('selector');
var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;

Це, здається, обчислюється вгорі документа, а не в області перегляду
Скотт Леонард

6

Ви можете спробувати:

node.offsetTop - window.scrollY

Він працює в Opera з визначеним метатегом перегляду.


7
Якщо я правильно розумію документацію , offsetTopстосується найближчого розміщеного елемента. Який, залежно від структури сторінки, може бути або не бути кореневим елементом.
Denilson Sá Maia

5

jQuery реалізує це досить елегантно. Якщо ви подивитесь на джерело jQuery offset, ви побачите, що це в основному як воно реалізовано:

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

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

2

Функція на цій сторінці поверне прямокутник з верхніми, лівими, координатами висоти та ширини переданого елемента відносно порту перегляду браузера.

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

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

джерело


1

Дякую за всі відповіді. Здається, у прототипу вже є функція, яка виконує цю функцію (page ()). Переглядаючи вихідний код функції, я виявив, що він спочатку обчислює положення зміщення елемента відносно сторінки (тобто верхній частині документа), а потім віднімає з цього scrollTop. Детальнішу інформацію див. У вихідному коді прототипу.


Гарне рішення. Можливо, найкраще працювати з однією з основних бібліотек, оскільки вони швидше дають однаковий результат у веб-переглядачах. Якщо вам цікаво, перевірте мою відповідь. Код там зробить це, але я поняття не маю, як він утримуватиметься в браузерах.
Дерек Свінглі

1

Я припускаю, що btn1на веб-сторінці існує елемент, який має ідентифікатор існування, а також включений jQuery. Це працює у всіх сучасних браузерах Chrome, FireFox, IE> = 9 та Edge. jQuery використовується лише для визначення позиції щодо документа.

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

var screenRelativeLeft =  $("#btn1").offset().left - (window.scrollX ||
                                           window.pageXOffset || document.body.scrollLeft);

1
jQuery - це JavaScript. Я вважаю, ви мали на увазі "це не 100% ваніль / чистий JS".
голод

Так, це я мав на увазі.
Суніль

1

Іноді getBoundingClientRect()значення властивості об'єкта показує 0 для IE. У цьому випадку ви повинні встановити display = 'block'елемент. Ви можете використовувати код нижче для всіх браузерів для компенсації.

Розширення функціональності 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));

Використання:

var elementOffset = $("#" + elementId).weOffset();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.