Получить позицию (X, Y) HTML-элемента относительно окна браузера

1570

Я хочу знать, как получить положение X и Y элементов HTML, таких как imgи divв JavaScript, относительно окна браузера.

Джек
источник
134
Относительно чего?
AnthonyWJones
4
я использовал эти 7 строк кода, который работает во всех браузерах с расхождениями в ie5,6,7 (я не помню, чтобы у меня был какой-то пробоем ... может быть, типа doc) ... quirksmode.org/js/findpos. HTML, и я использовал его много лет. Может быть, кто-то может указать недостатки, если таковые имеются.
Джаяпал Чандран
99
@AnthonyWJones, я полагаю, вам нужно было педантичное удовольствие, но очевидно, как всегда, когда не указано, что OP относится к наиболее общему случаю или к координатам окна браузера.
Моты
7
@ Mote, нет, это не так очевидно. Оставьте вывод, субъективность и ложные аксиомы в стороне. Это может быть относительно области просмотра или вершины страницы (также известный как document.documentElement).
Андре Фигейредо
16
По умолчанию самое общее - это не логический вывод, это логическая последовательность, так что это будет относительно окна, или «верх страницы» может быть термином, как вы его выразили. В теории игр она кодифицируется как концепция, называемая точкой Шеллинга. Обязательно укажите, когда вы не имеете в виду самый общий случай.
Motes

Ответы:

1797

Правильный подход заключается в использовании element.getBoundingClientRect():

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);

Internet Explorer поддерживает это до тех пор, пока вы, вероятно, будете заботиться об этом, и наконец он был стандартизирован в представлениях CSSOM . Все остальные браузеры приняли его давно .

Некоторые браузеры также возвращают свойства высоты и ширины, хотя это нестандартно. Если вас беспокоит совместимость с более старыми браузерами, проверьте исправления этого ответа для оптимизированной, унизительной реализации.

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

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

alert('Element is ' + offset + ' vertical pixels from <body>');
Энди Э
источник
144
Очень интересная статья на JS координаты . Эта статья нигде не упоминается на SO, она должна ..
e2-e4
6
Не работает ... это 8 пикселей по вертикали и горизонтали из-за поля в 8px в теле. Решение Меоу отлично работает. Если хотите, у меня есть небольшой тест, чтобы продемонстрировать проблему.
CpnCrunch
3
На самом деле, я думаю, что это зависит от того, что вы на самом деле хотите получить координаты. Вопрос немного двусмысленный. Ваш ответ верен, если вы просто хотите получить координаты относительно области просмотра или относительно элемента body, но это не поможет вам в том случае, если вы хотите абсолютную позицию элемента (что, как я думаю, является тем, чего хочет большинство людей) , Ответ meouw также не даст вам этого, если вы не удалите биты '-scrollLeft' и '-scrollTop'.
CpnCrunch
4
@CpnCrunch: теперь я понимаю, что вы имеете в виду; Я не понимал, что вы имели в виду последнюю часть моего ответа. Когда тело имеет поле, его ограничивающая рамка будет смещена на это количество пикселей на каждой соответствующей стороне. В этом случае вам также придется вычесть вычисленный стиль поля из координат тела. Стоит отметить, что сброс CSS приводит к удалению поля из <body>.
Энди Э
3
element.getBoundingClientRect().topне возвращает правильное верхнее смещение в случае position: fixedэлемента в iOS (iPhone 8), если он содержит сфокусированный элемент ввода и виртуальная клавиатура сдвинулась вверх. Например, если фактическое смещение от вершины окна составляет 200px, оно сообщит об этом как 420px, где 220px - высота виртуальной клавиатуры. Если вы установите элемент position: absoluteи разместите его в том же положении, как если бы он был зафиксирован, тогда вы получите правильные 200px. Я не знаю решения этого.
Янис Элмерис
327

Библиотеки идут на все, чтобы получить точные смещения для элемента.
Вот простая функция, которая делает работу при любых обстоятельствах, которые я пробовал.

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}
var x = getOffset( document.getElementById('yourElId') ).left; 
meouw
источник
14
изменить: el = el.parentNode на: el = el.offsetParent; и, похоже, теперь работает для вложенных фреймов ... Я думаю, это то, что вы хотели?
Адам
4
Это решение является неполным. Попробуйте поставить толстую границу на div и вложите его несколько раз. В любой версии Firefox (2-5) он будет отключен шириной (-ами) границы (даже в режиме соответствия стандартам).
ck_
3
нет ли более чистого способа сделать это, например, функции el.totalOffsetLeft и totalOffsetTop? jQuery, конечно, имеет эту опцию, но обидно, что нет официального метода для этого, нужно ли ждать DOM4? Я создаю приложение HTML5 canvas, поэтому я думаю, что лучшим решением было бы вставить элемент canvas в iframe, чтобы я мог получить реальные координаты с clientX и clientY, когда мы нажимаем на элемент.
baptx
1
Итак, @Adam и meouw, ты говоришь, что первый блок кода неправильный? Тогда почему бы не удалить это вообще? (Этот вопрос видел довольно много зрителей за эти годы; может быть, было бы неплохо убрать вещи, если они не правы?)
Арджан
2
@baptx: Я знаю, что это поздний ответ, но я раньше не видел ваш комментарий. Посмотрите мой ответ ниже для более совместимой с стандартами альтернативы - вам даже не нужен запасной код, так как браузеры уже давно его поддерживают.
Энди Э,
242

Это сработало для меня (модифицировано из ответов с наибольшим количеством голосов):

function getOffset(el) {
  const rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.scrollX,
    top: rect.top + window.scrollY
  };
}

Используя это мы можем позвонить

getOffset(element).left

или

getOffset(element).top
Адам Грант
источник
1
Только это решение работает для меня, когда элемент помещен в divцентр с использованием css top:50%, left:50%; transform:translate(-50%, -50%);... отлично. Согласитесь с вопросом @ScottBiggs. Логично стремиться к простоте.
nelek
3
может быть, это не победитель, потому что он такой же, как решение Энди Е., но не работает в старых браузерах <IE9
niltoid
getBoundingClientRect вызывает огромный всплеск перерисовки в моих графиках производительности
frumbert
1
Вы должны определить , rectиспользуя var, letили const. В противном случае он определяется как window.rect.
hev1
2
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)вернет среднее положение элемента
19
97

Если вы хотите, чтобы это было сделано только в JavaScript , вот некоторые из них, используяgetBoundingClientRect()

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

Первая строка вернет, offsetTopскажем, Y относительно документа. Вторая строка вернет, offsetLeftскажем, X относительно документа.

getBoundingClientRect() является функцией javascript, которая возвращает позицию элемента относительно окна просмотра окна.

Mustkeem K
источник
2
Это должно быть решением. Здесь нет длинного кода bs, он понятен и очень точен!
E Alexis MT
2
Что делать, если элемент находится внутри прокручиваемого элемента? Единственный способ сделать это - суммировать offsetTop всех родительских элементов, как предлагают другие ответы,
Дмитрий Писарев,
Как утверждает Дмитрий, это неправильно и очень некорректно. Он не должен иметь столько голосов, сколько имеет. Он также ВСЕГДА будет в элементе с возможностью прокрутки, потому что сам документ можно прокручивать. Другими словами, если весь документ не помещается в окне просмотра, он всегда будет неверным, если пользователь вообще прокрутил главное окно.
Лев
46

Элементы HTML в большинстве браузеров будут иметь: -

offsetLeft
offsetTop

Они определяют положение элемента относительно его ближайшего родителя, который имеет макет. К этому родителю часто можно получить доступ со свойством offsetParent.

IE и FF3 имеют

clientLeft
clientTop

Эти свойства менее распространены, они задают положение элементов в родительской клиентской области (заполненная область является частью клиентской области, а границы и поля - нет).

AnthonyWJones
источник
36

Если страница содержит, по крайней мере, какой-либо «DIV», функция, заданная meouw, выбрасывает значение «Y» за пределы текущей страницы. Чтобы найти точную позицию, вам нужно обработать как offsetParent, так и parentNode.

Попробуйте код, приведенный ниже (это проверено на FF2):


var getAbsPosition = function(el){
    var el2 = el;
    var curtop = 0;
    var curleft = 0;
    if (document.getElementById || document.all) {
        do  {
            curleft += el.offsetLeft-el.scrollLeft;
            curtop += el.offsetTop-el.scrollTop;
            el = el.offsetParent;
            el2 = el2.parentNode;
            while (el2 != el) {
                curleft -= el2.scrollLeft;
                curtop -= el2.scrollTop;
                el2 = el2.parentNode;
            }
        } while (el.offsetParent);

    } else if (document.layers) {
        curtop += el.y;
        curleft += el.x;
    }
    return [curtop, curleft];
};
Рефик Аята
источник
1
как и в других решениях даже с FF 24.4, вышеприведенный код не работает, когда ширины границ существуют как часть макета позиционирования.
грабить
Вы спасатель. Я работаю над некоторыми довольно глубокими ошибками GWT прямо сейчас, и добавление этого в метод JSNI решает все мои проблемы !!
Уилл Бирн
35

Вы можете добавить два свойства, чтобы Element.prototypeполучить верхнюю / левую часть любого элемента.

Object.defineProperty( Element.prototype, 'documentOffsetTop', {
    get: function () { 
        return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 );
    }
} );

Object.defineProperty( Element.prototype, 'documentOffsetLeft', {
    get: function () { 
        return this.offsetLeft + ( this.offsetParent ? this.offsetParent.documentOffsetLeft : 0 );
    }
} );

Это называется так:

var x = document.getElementById( 'myDiv' ).documentOffsetLeft;

Вот демонстрация, сравнивающая результаты с jQuery offset().topи .left: http://jsfiddle.net/ThinkingStiff/3G7EZ/

ThinkingStiff
источник
14
модификация Element.prototypeвообще считается плохой идеей . Это приводит к очень сложному обслуживанию кода. Кроме того, этот код не учитывает прокрутку.
Джаред Форсайт
23

Чтобы получить позицию относительно страницы эффективно и без использования рекурсивной функции: (также включает IE)

var element = document.getElementById('elementId'); //replace elementId with your element's Id.
var rect = element.getBoundingClientRect();
var elementLeft,elementTop; //x and y
var scrollTop = document.documentElement.scrollTop?
                document.documentElement.scrollTop:document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft?                   
                 document.documentElement.scrollLeft:document.body.scrollLeft;
elementTop = rect.top+scrollTop;
elementLeft = rect.left+scrollLeft;
Абдул Рахим Хаддад
источник
Включение всех важных scrollTop / scrollLeft делает этот ответ немного более правильным.
scunliffe
19

Как насчет чего-то подобного, передав ID элемента, и он вернётся влево или вверх, мы также можем объединить их:

1) найти слева

function findLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.left + window.scrollX;
} //call it like findLeft('#header');

2) найти топ

function findTop(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.top + window.scrollY;
} //call it like findTop('#header');

или 3) найти слева и сверху вместе

function findTopLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return {top: rec.top + window.scrollY, left: rec.left + window.scrollX};
} //call it like findTopLeft('#header');
Алиреза
источник
16

Возможно, вам лучше будет использовать JavaScript-фреймворк, в котором есть функции для возврата такой информации (и многое другое!) Независимо от браузера. Вот несколько из них:

С помощью этих структур вы можете сделать что-то вроде: $('id-of-img').top получить координату Y-пикселя изображения.

Шалом Креймер
источник
2
@Costa Все они используют эти виды функций, хотя это развивающееся поле, поскольку разные браузеры по-разному соответствуют спецификации. Большая часть кода посвящена исправлению ошибок. Вы действительно должны смотреть на исходный код.
Шалом Креймер
18
@scraimer: jQuery и YUI НЕ являются фреймворками !!! Это библиотеки ! Это не тоже самое. Ссылаясь на jquery.com : «jQuery - это быстрая, небольшая и многофункциональная библиотека JavaScript ». Ссылаясь на yuilibrary.com (вы также можете увидеть «волшебное» слово в URL-адресе ...): «YUI - это бесплатная библиотека JavaScript и CSS с открытым исходным кодом для создания многофункциональных интерактивных веб-приложений».
Sk8erPeter
29
Таким образом, вы должны использовать огромные библиотеки только для этой простой задачи? Не обязательно. Я ненавижу, что каждый раз, когда я хочу что-то сделать с js, я получаю эти решения jQuery. JQuery это не JS!
Опптатт Джоббер
1
@ OpppattJobber Я согласен ... JQuery не является JavaScript. Он опирается на Javascript, но это совершенно другой язык программирования.
Ник Мэннинг
5
@NickManning Это не новый язык, это уровень абстракции для DOM, который избавляет от необходимости записывать обходные пути совместимости и производительности непосредственно в ваш код. Если вы не используете jQuery, вы все равно должны использовать какой-либо слой абстракции.
Джинман
15

jQuery .offset () получит текущие координаты первого элемента или установит координаты каждого элемента в наборе совпадающих элементов относительно документа.

akauppi
источник
По некоторым причинам он не дает такие же результаты в IE по сравнению с другими браузерами. Я думаю, что в IE это дает положение относительно окна, поэтому, если вы прокрутите, вы получите в IE разные результаты по сравнению с другими
Абдул Рахим Хаддад
1
Смещение () сбивает с толку масштабирование, по крайней мере, в Android Chrome, поэтому оно бесполезно. stackoverflow.com/a/11396681/1691517 показывает толерантный к масштабированию способ.
Тимо Кяхконен
10

Я взял ответ @ meouw, добавил в clientLeft, который учитывает границы, а затем создал три версии:

getAbsoluteOffsetFromBody - по аналогии с @ meouw, он получает абсолютную позицию относительно тела или html-элемента документа (в зависимости от режима причуд)

getAbsoluteOffsetFromGivenElement - возвращает абсолютную позицию относительно данного элемента (lativeEl). Обратите внимание, что данный элемент должен содержать элемент el, иначе он будет вести себя так же, как getAbsoluteOffsetFromBody. Это полезно, если у вас есть два элемента, содержащихся в другом (известном) элементе (необязательно, несколько узлов вверх по дереву узлов) и вы хотите сделать их одинаковыми.

getAbsoluteOffsetFromRelative - возвращает абсолютную позицию относительно первого родительского элемента с position :lative. Это похоже на getAbsoluteOffsetFromGivenElement, по той же причине, но будет идти только до первого соответствующего элемента.

getAbsoluteOffsetFromBody = function( el )
{   // finds the offset of el from the body or html element
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromGivenElement = function( el, relativeEl )
{   // finds the offset of el from relativeEl
    var _x = 0;
    var _y = 0;
    while( el && el != relativeEl && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

getAbsoluteOffsetFromRelative = function( el )
{   // finds the offset of el from the first parent with position: relative
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
    {
        _x += el.offsetLeft - el.scrollLeft + el.clientLeft;
        _y += el.offsetTop - el.scrollTop + el.clientTop;
        el = el.offsetParent;
        if (el != null)
        {
            if (getComputedStyle !== 'undefined')
                valString = getComputedStyle(el, null).getPropertyValue('position');
            else
                valString = el.currentStyle['position'];
            if (valString === "relative")
                el = null;
        }
    }
    return { top: _y, left: _x };
}

Если у вас все еще есть проблемы, особенно связанные с прокруткой, вы можете попробовать посмотреть на http://www.greywyvern.com/?post=331 - я заметил по крайней мере один фрагмент сомнительного кода в getStyle, который должен быть нормальным, если браузеры ведут себя хорошо , но все остальное не проверял.

Джеймс Карлайл-Кларк
источник
Интересно ... но в Edge getAbsoluteOffsetFromBody (element) .top возвращает другое значение при прокрутке, в Chrome оно остается неизменным при прокрутке. Кажется, Edge корректируется с помощью позиции прокрутки. Когда элемент прокручивается из поля зрения, я получаю отрицательное значение.
Норман,
getAbsoluteOffsetFromRelative сделал мой день, мне пришлось воспроизводить всплывающую подсказку без Javascript начальной загрузки, это мне очень помогло.
Nolyurn
На всякий случай, если Meouw изменит свое имя пользователя, ссылка на ответ: stackoverflow.com/a/442474/3654837 . (Я не хочу поднимать эту старую
ветку,
8

при использовании jQuery плагин размеров превосходен и позволяет вам точно указать, что вы хотите.

например

Относительная позиция, абсолютная позиция, абсолютная позиция без заполнения, с заполнением ...

Это продолжается, скажем так, с этим можно многое сделать.

Плюс преимущество использования jQuery - это легкий размер файла и простота использования, после чего вы не вернетесь к JavaScript без него.

John_
источник
8

Это лучший код, который мне удалось создать (работает также в iframes, в отличие от смещения jQuery ()). Кажется, у webkit немного другое поведение.

На основании комментария Мёу:

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        // chrome/safari
        if ($.browser.webkit) {
            el = el.parentNode;
        } else {
            // firefox/IE
            el = el.offsetParent;
        }
    }
    return { top: _y, left: _x };
}
Рон Рейтер
источник
Обратите внимание, что вам нужно jQueryиспользовать $.browser.webkit; Вам нужно будет поиграться, navigator.userAgentчтобы сделать то же самое с чистым JavaScript.
SP
2
$ .browser больше не доступен в последней версии jQuery
Gus
к сожалению, даже с FF 24.4 приведенный выше код не работает, когда ширины границ существуют как часть компоновки позиционирования.
грабить
8

Если вы используете jQuery, это может быть простое решение:

<script>
  var el = $("#element");
  var position = el.position();
  console.log( "left: " + position.left + ", top: " + position.top );
</script>
Адам Бустани
источник
8

Разница между маленьким и маленьким

function getPosition( el ) {
    var x = 0;
    var y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
    x += el.offsetLeft - el.scrollLeft;
    y += el.offsetTop - el.scrollTop;
    el = el.offsetParent;
    }
    return { top: y, left: x };
}

Посмотрите пример координат: http://javascript.info/tutorial/coordinates

KingRider
источник
К сожалению, это не работает для всех элементов, которые можно найти в современном HTML-документе. Встроенные <svg>элементы, например, не имеют offsetLeft, offsetTopи offsetParentсвойства.
Джонатан Юнис
Просто DIVили IMGнет SVG. Посмотреть "Посмотреть пример координат"? Вы можете найти объект svg в позиции вызова getOffsetRect , попробуйте и зависит от работы объекта.
KingRider
7

Самый чистый подход, который я нашел, - это упрощенная версия техники, используемой jQuery offset. Как и в некоторых других ответах, он начинается с getBoundingClientRect; Затем он использует windowи documentElementдля корректировки позиции прокрутки, а также такие вещи, как поля на body(часто по умолчанию).

var rect = el.getBoundingClientRect();
var docEl = document.documentElement;

var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;

Джеймс Монтань
источник
6

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

Ситуация :
на странице HTML5 у меня было меню, которое было элементом nav внутри заголовка (не заголовок THE, а заголовок другого элемента).
Я хотел, чтобы навигация прилипала к вершине, как только пользователь прокручивал ее, но до этого заголовок располагался в абсолютном положении (поэтому я мог немного перекрыть его).
Приведенные выше решения никогда не вызывали изменений, потому что .offsetTop не собирался меняться, поскольку это был элемент с абсолютным позиционированием. Кроме того, свойство .scrollTop было просто вершиной самого верхнего элемента ... то есть 0 и всегда будет 0.
Любые тесты, которые я выполнял, используя эти два (и то же самое с результатами getBoundingClientRect), не сообщали бы мне, прокручивалась ли верхняя часть панели навигации до верхней части просматриваемой страницы (опять же, как сообщалось в консоли, они просто оставались теми же числами при прокрутке). произошло).

Решение
Решение для меня было использование

window.visualViewport.pageTop

Значение свойства pageTop отражает видимую часть экрана, поэтому я могу отслеживать, где находится элемент относительно границ видимой области.

Вероятно, нет необходимости говорить, что всякий раз, когда я имею дело с прокруткой, я ожидаю использовать это решение для программной реакции на движение прокручиваемых элементов.
Надеюсь, это поможет кому-то еще.
ВАЖНОЕ ПРИМЕЧАНИЕ: Это, кажется, работает в Chrome и Opera в настоящее время и определенно не в Firefox (6-2018) ... пока Firefox не поддерживает VisualViewport, я рекомендую НЕ использовать этот метод, (и я надеюсь, что они скоро сделают ... это многое делает больше смысла, чем у остальных).


ОБНОВЛЕНИЕ:
только примечание относительно этого решения.
Хотя я все еще нахожу, что обнаружил, что это очень ценно для ситуаций, в которых «... программно реагирует на движение прокручиваемых элементов». применимо. Лучшее решение для моей проблемы было использовать CSS для установки позиции: stickyна элементе. Используя sticky, вы можете оставить элемент наверху без использования javascript (ПРИМЕЧАНИЕ: бывают случаи, когда это не будет работать так же эффективно, как изменение элемента на fixed, но для большинства применений липкий подход, вероятно, будет лучше)

UPDATE01:
Итак, я понял, что для другой страницы у меня было требование, в котором мне нужно было определить положение элемента в слегка сложной настройке прокрутки (параллакс плюс элементы, которые прокручиваются мимо как часть сообщения). В этом сценарии я понял, что следующие данные предоставляют значение, которое я использовал, чтобы определить, когда что-то делать:

  let bodyElement = document.getElementsByTagName('body')[0];
  let elementToTrack = bodyElement.querySelector('.trackme');
  trackedObjPos = elementToTrack.getBoundingClientRect().top;
  if(trackedObjPos > 264)
  {
    bodyElement.style.cssText = '';
  }

Надеюсь, что этот ответ более полезен сейчас.

MER
источник
это очень вероятно, чтобы быть в верхней части очень многих ответов, когда вы нажимаете активный, чтобы отсортировать ответы
lucchi
@lucchi: D хорошо, я полагаю, я мог бы удалить текст @ сверху ... хотя я только что повторил этот вопрос и понял, что нашел лучшее решение для своей проблемы ... хотя мой ответ скорее обратите внимание на более полные ответы. Я подозреваю, что мои требования были не настолько распространены, чтобы другие ответы не работали для меня?
MER
1
В любом случае, я ценю ваш ответ, просто хочу сказать, что любой желающий будет знать, что вы написали что-то новое. Вы не одиноки ....
Луччи
5

Я сделал это так, чтобы он был совместим со старыми браузерами.

// For really old browser's or incompatible ones
    function getOffsetSum(elem) {
        var top = 0,
            left = 0,
            bottom = 0,
            right = 0

         var width = elem.offsetWidth;
         var height = elem.offsetHeight;

        while (elem) {
            top += elem.offsetTop;
            left += elem.offsetLeft;
            elem = elem.offsetParent;
        }

         right = left + width;
         bottom = top + height;

        return {
            top: top,
            left: left,
            bottom: bottom,
            right: right,
        }
    }

    function getOffsetRect(elem) {
        var box = elem.getBoundingClientRect();

        var body = document.body;
        var docElem = document.documentElement;

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

        var clientTop = docElem.clientTop;
        var clientLeft = docElem.clientLeft;


        var top = box.top + scrollTop - clientTop;
        var left = box.left + scrollLeft - clientLeft;
        var bottom = top + (box.bottom - box.top);
        var right = left + (box.right - box.left);

        return {
            top: Math.round(top),
            left: Math.round(left),
            bottom: Math.round(bottom),
            right: Math.round(right),
        }
    }

    function getOffset(elem) {
        if (elem) {
            if (elem.getBoundingClientRect) {
                return getOffsetRect(elem);
            } else { // old browser
                return getOffsetSum(elem);
            }
        } else
            return null;
    }

Подробнее о координатах в JavaScript здесь: http://javascript.info/tutorial/coordinates

Боян Ксенеман
источник
4

Чтобы получить общее смещение элемента, вы можете рекурсивно суммировать все родительские смещения:

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

с помощью этой вспомогательной функции общее верхнее смещение элемента dom:

el.offsetTop + getParentOffsets(el);
Кевин К.
источник
3
/**
 *
 * @param {HTMLElement} el
 * @return {{top: number, left: number}}
 */
function getDocumentOffsetPosition(el) {
    var position = {
        top: el.offsetTop,
        left: el.offsetLeft
    };
    if (el.offsetParent) {
        var parentPosition = getDocumentOffsetPosition(el.offsetParent);
        position.top += parentPosition.top;
        position.left += parentPosition.left;
    }
    return position;
}

Спасибо ThinkingStiff за ответ , это всего лишь еще одна версия.

Văn Quyết
источник
2

Я успешно использовал решение Энди Э. для позиционирования модуса начальной загрузки 2 в зависимости от того, на какую ссылку в строке таблицы нажимает пользователь. Страница представляет собой страницу «Гобелен 5», и приведенный ниже JavaScript импортируется в класс страниц Java.

JavaScript:

function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset   = elemRect.top - bodyRect.top;
offset   = offset + 20;
$('#serviceLineModal').css("top", offset);

}

Мой модальный код:

<div id="serviceLineModal" class="modal hide fade add-absolute-position" data-backdrop="static" 
 tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="top:50%;">
<div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
    <h3 id="myModalLabel">Modal header</h3>
</div>

<div class="modal-body">
    <t:zone t:id="modalZone" id="modalZone">
        <p>You selected service line number: ${serviceLineNumberSelected}</p>
    </t:zone>
</div>

<div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <!-- <button class="btn btn-primary">Save changes</button> -->
</div>

Ссылка в цикле:

<t:loop source="servicesToDisplay" value="service" encoder="encoder">
<tr style="border-right: 1px solid black;">       
    <td style="white-space:nowrap;" class="add-padding-left-and-right no-border"> 
        <a t:type="eventLink" t:event="serviceLineNumberSelected" t:context="service.serviceLineNumber" 
            t:zone="pageZone" t:clientId="modalLink${service.serviceLineNumber}"
            onmouseover="setLinkPosition(this);">
            <i class="icon-chevron-down"></i> <!-- ${service.serviceLineNumber} -->
        </a>
    </td>

И код Java в классе страницы:

void onServiceLineNumberSelected(String number){
    checkForNullSession();
    serviceLineNumberSelected = number;
    addOpenServiceLineDialogCommand();
    ajaxResponseRenderer.addRender(modalZone);
}

protected void addOpenServiceLineDialogCommand() {
    ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
        @Override
        public void run(JavaScriptSupport javascriptSupport) {
            javascriptSupport.addScript("$('#serviceLineModal').modal('show');");
        }
    });
}

Надеюсь, это поможет кому-то, этот пост помог.

Марк Эспиноза
источник
Этот js-код помог мне, у меня есть старое приложение webforms, использующее множественные заполнители для вставки страниц .aspx, и я не мог понять, как добавить appendChild () из всплывающего окна, которое я создавал, чтобы получить его в окне просмотра, потому что все дерево DOM не работает с несколькими заполнителями и неправильной разметкой. Использование body.getBoundingClientRect (), а затем использование его вершины в позиционировании было тем, что мне было нужно. Спасибо.
Брэд Мартин
1

После долгих исследований и испытаний это, кажется, работает

function getPosition(e) {
    var isNotFirefox = (navigator.userAgent.toLowerCase().indexOf('firefox') == -1);
    var x = 0, y = 0;
    while (e) {
        x += e.offsetLeft - e.scrollLeft + (isNotFirefox ? e.clientLeft : 0);
        y += e.offsetTop - e.scrollTop + (isNotFirefox ? e.clientTop : 0);
        e = e.offsetParent;
    }
    return { x: x + window.scrollX, y: y + window.scrollY };
}

см. http://jsbin.com/xuvovalifo/edit?html,js,output

kernowcode
источник
1

Просто подумал, что я тоже это выброшу.
Я не смог протестировать его в старых браузерах, но он работает в последней версии топ-3 :)

Element.prototype.getOffsetTop = function() {
    return ( this.parentElement )? this.offsetTop + this.parentElement.getOffsetTop(): this.offsetTop;
};
Element.prototype.getOffsetLeft = function() {
    return ( this.parentElement )? this.offsetLeft + this.parentElement.getOffsetLeft(): this.offsetLeft;
};
Element.prototype.getOffset = function() {
    return {'left':this.getOffsetLeft(),'top':this.getOffsetTop()};
};
Дункан
источник
0

Так как разные браузеры по-разному отображают границы, отступы, поля и т. Д. Я написал небольшую функцию, чтобы получить верхнюю и левую позиции определенного элемента в каждом корневом элементе, который вы хотите в точном измерении:

function getTop(root, offset) {
    var rootRect = root.getBoundingClientRect();
    var offsetRect = offset.getBoundingClientRect();
    return offsetRect.top - rootRect.top;
}

Для восстановления левой позиции вы должны вернуть:

    return offsetRect.left - rootRect.left;
samadadi
источник
-1

Получить положение div относительно слева и сверху

  var elm = $('#div_id');  //get the div
  var posY_top = elm.offset().top;  //get the position from top
  var posX_left = elm.offset().left; //get the position from left 
Вишал
источник
Я проголосовал вниз, потому что нижний и правый не являются свойствами offset ()
MacroMan
@MacroMan, я уважаю ваше решение, но я уже объяснил в тексте, что «нижний и правый код не проверен». Кроме того, я обновлю свой код очень скоро.
Вишал
Я думаю, что el.offsetTopи el.offsetLeft(ОП ничего не говорит о jQuery ... Я не уверен, почему ваш ответ также использует jQuery ...)
mesqueeb