Определение положения элемента относительно документа

113

Какой самый простой способ определить положение элементов относительно окна документа / тела / браузера?

Прямо сейчас я использую .offsetLeft/offsetTop, но этот метод дает вам только положение относительно родительского элемента, поэтому вам нужно определить, сколько родителей у элемента body, чтобы узнать положение относительно положения тела / окна браузера / документа.

Этот метод также слишком громоздкий.

Einstein
источник

Ответы:

59

Вы можете offsetParentперейти на верхний уровень модели DOM.

function getOffsetLeft( elem )
{
    var offsetLeft = 0;
    do {
      if ( !isNaN( elem.offsetLeft ) )
      {
          offsetLeft += elem.offsetLeft;
      }
    } while( elem = elem.offsetParent );
    return offsetLeft;
}
КитсКеллехер
источник
28
Нет, это не так, когда любой родитель (особенно элемент html !!!) имеет поля, отступы или границы.
Flash Thunder
что касается полей ... это может помочь установить размер поля на border-box ... или что-то в этом роде ... ничего, что нельзя исправить ...
Во-первых, вам нужно решить, следует ли учитывать границы и поля в соответствии с размером блока. Во-вторых, следует учитывать свернутую маржу. И, наконец, в будущем будет более сложная ситуация, которая ухудшит этот ответ.
xianshenglu
6
Почему это принятый ответ? Это устарело и плохо работает. Сделайте себе одолжение и используйте getBoundingClientRect (), как предлагается в других ответах.
Фабиан фон Эллертс
177

Вы можете попасть наверх и влево, не пересекая DOM, вот так:

function getCoords(elem) { // crossbrowser version
    var box = elem.getBoundingClientRect();

    var body = document.body;
    var docEl = document.documentElement;

    var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
    var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;

    var clientTop = docEl.clientTop || body.clientTop || 0;
    var clientLeft = docEl.clientLeft || body.clientLeft || 0;

    var top  = box.top +  scrollTop - clientTop;
    var left = box.left + scrollLeft - clientLeft;

    return { top: Math.round(top), left: Math.round(left) };
}
Бэзил
источник
6
В этом ответе не учтены замещения родителей. Это только относительно области просмотра
Ники
3
@Nickey, это неправда - позиция области просмотра плюс проверки смещения прокрутки дают координаты относительно всего документа.
натчикета
1
Может быть багги на мобильных устройствах stackoverflow.com/a/32623832/962634 нужны исследования
базилик
1
Почему вы вычитаете clientTop / clientLeft?
Teemoh
1
@Teemoh clientTop / clientLeft соответствует значениям границ <html>элемента.
Raphael Rafatpanah
98

Вы можете использовать element.getBoundingClientRect()для получения позиции элемента относительно области просмотра.

Затем используйте document.documentElement.scrollTopдля вычисления смещения области просмотра.

Сумма двух даст положение элемента относительно документа:

element.getBoundingClientRect().top + document.documentElement.scrollTop
dy_
источник
10
Относительно области просмотра не то же самое, что относительно документа. Если страница немного прокручена вниз, то верхнее положение относительно области просмотра будет меньшим числом, чем верхнее положение относительно документа.
MrVimes
14
он начинает относительно области просмотра и добавляет scrollY, чтобы получить его относительно документа.
Хоакин Куэнка Абела
2
document.documentElement.scrollTopне работает в Safari, используйте window.scrollYвместо этого
Fabian von Ellerts 08
7

Я предлагаю использовать

element.getBoundingClientRect()

как предлагается здесь вместо ручного расчета смещения через offsetLeft , offsetTop и offsetParent . как предлагается здесь. При некоторых обстоятельствах * обход вручную дает недопустимые результаты. См. Этот Plunker: http://plnkr.co/pC8Kgj

* Когда элемент находится внутри прокручиваемого родителя со статическим (= по умолчанию) позиционированием.

HANiS
источник
Вы также можете заставить вычисление смещения работать, включив в него scrollLeft и scrollTop.
Ben J
Но я нашел offsetLeftи offsetTopне принимаю во внимание преобразования CSS3, а это getBoundingClientRect()действительно так. Так что в этом случае результаты могут быть недействительными. Если вам это нужно, вы можете получить смещение элемента относительно родительского (например offsetLeft), используя (element.getBoundingClientRect().left - parent.getBoundingClientRect().left).
Ben J
должен обязательно подняться выше; эти значения гораздо более полезны, и все они в одном вызове!
mix3d 01
7

document-offset( Сторонний скрипт ) интересен, и, похоже, он использует подходы из других ответов здесь.

Пример:

var offset = require('document-offset')
var target = document.getElementById('target')
console.log(offset(target))
// => {top: 69, left: 108} 
Матье М-Госслен
источник
5

Я считаю, что следующий метод является наиболее надежным при работе с крайними случаями, которые приводят к отключению offsetTop / offsetLeft.

function getPosition(element) {
    var clientRect = element.getBoundingClientRect();
    return {left: clientRect.left + document.body.scrollLeft,
            top: clientRect.top + document.body.scrollTop};
}
Робин Стюарт
источник
4

Для тех, кто хочет получить координаты x и y различных положений элемента относительно документа.

const getCoords = (element, position) => {
  const { top, left, width, height } = element.getBoundingClientRect();
  let point;
  switch (position) {
    case "top left":
      point = {
        x: left + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "top center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "top right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "center left":
      point = {
        x: left + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "center right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "bottom left":
      point = {
        x: left + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
    case "bottom center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
    case "bottom right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
  }
  return point;
};

использование

  • getCoords(document.querySelector('selector'), 'center')

  • getCoords(document.querySelector('selector'), 'bottom right')

  • getCoords(document.querySelector('selector'), 'top center')

Рафаэль Рафатпанах
источник
2

Если вы не против использования jQuery, вы можете использовать offset()функцию. Обратитесь к документации, если вы хотите узнать больше об этой функции.

Адам
источник
1

http://www.quirksmode.org/js/findpos.html Объясняет лучший способ сделать это. В общем, вы на правильном пути, вам нужно найти смещения и пройти вверх по дереву родителей.

Джейк Калстад
источник