Как получить верхнюю позицию элемента относительно окна просмотра браузера?


173

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

Большое спасибо


2
Я думаю, что этот вопрос похож на stackoverflow.com/questions/211703/…, который имеет действительно хорошее решение.
Якоб Рунге

1
@JakobRunge, это было "хорошо" в 2013 году?
Юлиан

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

Ответы:


306

Существующие ответы сейчас устарели. Нативный getBoundingClientRect()метод существует уже довольно давно и делает именно то, о чем просит вопрос. Плюс это поддерживается во всех браузерах (включая IE 5, кажется!)

Со страницы MDN :

Возвращаемым значением является объект TextRectangle, который содержит свойства left, top, right и bottom, доступные только для чтения, описывающие рамку в пикселях, причем верхний левый угол относительно верхнего левого угла области просмотра .

Вы используете это так:

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
Денилсон Са Майя

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
Спасибо за ваш ответ, но я думаю, что вы неправильно поняли мой вопрос. Я знаю, как получить верхнюю часть элемента относительно страницы, и я пытаюсь получить позицию относительно «области просмотра» (т. Е. Окна браузера. , а не документ)
Валид Эйсса

Извините, ваше использование 'viewport' бросило меня. Итак, вы говорите, что хотите учесть браузер Chrome, то есть панель инструментов закладок, панель местоположения и т. Д.?
Дерек Суингли

Нет, просто окно, через которое вы видите страницу. Если страница прокручивается, она будет отличаться от верхней части документа, в противном случае они будут одинаковыми.
Валид Эйсса

О, хорошо, я понимаю. Не уверен, как это сделать ... отредактирую мой ответ, если я что-нибудь придумаю.
Дерек Суингли

Я сделал приведенный выше код немного страшнее, но он работает ... используйте 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 с определенным метатегом viewport.


7
Если я правильно понимаю документацию , это offsetTopотносится к ближайшему расположенному элементу. Который, в зависимости от структуры страницы, может быть или не быть корневым элементом.
Денилсон Са Майя

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

Функция на этой странице возвращает прямоугольник с координатами top, left, height и width переданного элемента относительно порта просмотра браузера.

    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

Спасибо за ответы на все вопросы. Кажется, в Prototype уже есть функция, которая делает это (функция 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».
Hungerstar

Да, это то, что я имел в виду.
Сунил

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.