Я хочу знать, как получить положение X и Y элементов HTML, таких как img и div, в JavaScript относительно окна браузера.
@AnthonyWJones, я полагаю, вам нужно было педантичное удовольствие, но очевидно, как всегда, когда не указано иное, что OP относится к наиболее общему случаю или относится к координатам окна браузера.
Ответ @ AndyE - явный победитель - не могли бы вы отметить принятый ответ, чтобы другим не пришлось читать 10 других ответов, чтобы добраться до него?
Здравствуйте, мистер Грег. Можете ли вы решить эту мою проблему .. Я только что опубликовал свою ссылку. Нажмите ее один раз stackoverflow.com/questions/41743667/…
@Mote, нет, это не так уж и очевидно. Оставьте в стороне умозаключения, субъективность и ложные аксиомы. Это может быть относительно области просмотра или верхней части страницы (также известный как document.documentElement).
Использование по умолчанию наиболее общего - это не вывод, это логическая последовательность, так что это будет относиться к окну или «верх страницы» может быть термином, как вы его выразили. В теории игр это кодифицировано как понятие, называемое точкой Шеллинга. Обязательно укажите, когда вы не имеете в виду самый общий случай.
Дело в том, что очевидное для одних не очевидно для других. Даже если теоретически мы знаем, что именно так, благодаря эмпирическим знаниям, ясность здесь никому не повредит, особенно тем, кто только начал программировать.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Элементы HTML в большинстве браузеров будут иметь: -
offsetLeft
offsetTop
Они определяют положение элемента относительно его ближайшего родителя, имеющего макет. К этому родительскому элементу часто можно получить доступ через свойство offsetParent.
IE и FF3 имеют
clientLeft
clientTop
Эти свойства менее распространены, они определяют положение элемента вместе с его родительской клиентской областью (заполненная область является частью клиентской области, а граница и поля - нет).
как это ответить на вопрос, который должен получить позицию элемента относительно окна браузера, а не только родительского элемента?
Возможно, вам будет лучше использовать фреймворк JavaScript, который имеет функции для возврата такой информации (и многого другого!) Независимо от браузера. Вот несколько:
С помощью этих фреймворков вы могли бы сделать что-то вроде:
$('id-of-img').top
чтобы получить координату y-пикселя изображения.
Вы знаете, чем отличаются реализации? Используют ли библиотеки функции, похожие на перечисленные выше?
@Costa Все они используют такие функции, хотя эта область постоянно развивается, поскольку разные браузеры по-разному соответствуют спецификации. Большая часть кода связана с «исправлением» того, что идет не так. Вам действительно стоит посмотреть исходный код.
Я пытался сделать именно это и нашел это очень полезным: james.padolsey.com/jquery У меня была странная проблема с исходным кодом библиотеки, каждый раз, когда я пытаюсь отформатировать его с помощью плагина beautifier или текстового редактора, я все равно получаю код javascript на две строчки.
@scraimer: jQuery и YUI - это НЕ рамки !!! Это библиотеки! Это не одно и то же. Цитирование jquery.com: «jQuery - это быстрый, небольшой и многофункциональный JavaScript библиотека». Цитирование yuilibrary.com (вы также можете увидеть "волшебное" слово в URL ...): «YUI - это бесплатный JavaScript и CSS библиотека с открытым исходным кодом для создания полнофункциональных интерактивных веб-приложений».
Значит, вы должны использовать огромные библиотеки только для этой простой задачи? Не обязательно. Я ненавижу то, что каждый раз, когда я хочу что-то сделать с js, я получаю эти решения jQuery. jQuery - это не JS!
@OpptattJobber Я согласен ... JQuery - это не javascript. Он полагается на Javascript, но это совершенно другой язык программирования.
@NickManning Это не новый язык, это уровень абстракции для DOM, который избавляет от необходимости писать обходные пути совместимости и производительности непосредственно в ваш код. Если вы не используете jQuery, вам в любом случае следует использовать какой-то уровень абстракции.
jQuery написан на javascript, так как же это может быть совсем другой язык ... да ладно.
Хотя это отличное предложение, это не прямой ответ на вопрос, оставьте это для комментариев. И поздравляю вас с тем, что вы знаете так много фреймворков, просто JQuery достаточно запутан, чтобы изучать больше фреймворков, потому что фреймворки имеют огромный недостаток, программист, который пишет фреймворк, думает не так, как вы, и, следовательно, очень трудно следовать их логике. В отличие от библиотек, которые просто предоставляют какой-то API, который позволяет делать четкие вещи, и, тем не менее, иногда, например, в библиотеках c, вы не знаете, нужно ли что-то free() или нет!
Я должен добавить к этому дополнительный комментарий, чтобы прояснить все «фреймворк» против «библиотеки». Фреймворк - это что-то построенное, чтобы действовать как слой вокруг или поверх чего-то другого. Библиотека - это собрание чего-то. На мой взгляд, jQuery (+ аналогичные) - это «фреймворки», которые полагаются на Javascript для создания «библиотеки» инструментов, ускоряющих выполнение задач. Вам не нужно самостоятельно учиться делать это, используя необработанный Javascript, или беспокоиться о совместимости браузера. Вы растете, чтобы учиться и полагаться на их методы и пользовательские функции Javascript. Отлично подходит для ускорения больших задач, но может раздуть более мелкие.
Библиотеки идут на все, чтобы получить точные смещения для элемента. вот простая функция, которая работает в любых обстоятельствах, которые я пробовал.
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;
изменить: el = el.parentNode на: el = el.offsetParent; и, похоже, теперь он работает для вложенных фреймов ... Я думаю, это то, что вы хотели?
Это решение неполное. Попробуйте поставить толстую рамку на div и несколько раз вложить ее. В любой версии Firefox (2–5) он будет отключен по ширине (а) границ (даже в режиме соответствия стандартам).
Вам также может понадобиться сделать _y+=Math.abs(document.body.offsetTop) и _x+=Math.abs(document.body.offsetLeft) для Firefox.
нет ли более чистого способа сделать это, например, функций el.totalOffsetLeft и totalOffsetTop? В jQuery есть такая возможность, но жаль, что для этого нет официального метода, нужно ли нам ждать DOM4? Я создаю приложение холста HTML5, поэтому я думаю, что лучшим решением было бы вставить элемент холста в iframe, чтобы я мог получать реальные координаты с clientX и clientY, когда мы нажимаем на элемент.
Итак, @Adam и meouw, вы говорите, что первый блок кода неправильный? Тогда почему бы не удалить это вообще? (Этот вопрос задавали довольно много зрителей на протяжении многих лет; было бы неплохо удалить вещи, если они ошибаются?)
(Кстати: блоки кода обсуждаются на Что делать, если кто-то добавляет альтернативный код с минимальными изменениями?, @Adam и meouw.)
@baptx: Я знаю, что это запоздалый ответ, но я не увидел ваш комментарий раньше. См. Мой ответ ниже для получения альтернативы, более соответствующей стандартам - вам даже не нужен резервный код, поскольку браузеры уже давно поддерживают его.
Эй, спасибо за ответ! Я все еще получаю неточные результаты. Вот мой код: stackoverflow.com/questions/15648464/…
Для IE4 + (четыре) этого делать не нужно. См. Энди ответ.
Смещение не работает точно в некоторых браузерах при масштабировании, можете посоветовать?
Также не будет работать для элементов svg (<svg>, <g>, path> и т. д.)
Ошибки в мобильном Chrome для iOS, используйте вместо ответа Адама Гранта stackoverflow.com/a/28222246/1025702
при использовании jQuery плагин размеров отлично подходит и позволяет вам точно указать, что вы хотите.
например
Относительное положение, абсолютное положение, абсолютное положение без заполнения, с заполнением ...
Это продолжается, давайте просто скажем, что вы можете многое с этим сделать.
Плюс к этому бонус от использования jQuery - это легкий размер файла и простота использования, вы не вернетесь к JavaScript без него впоследствии.
Если страница включает - по крайней мере - любой «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];
};
как и в случае с другими решениями, даже с FF 24.4 приведенный выше код не работает, когда ширина границ существует как часть макета позиционирования.
Ты спасатель. Я работаю над некоторыми довольно серьезными ошибками GWT прямо сейчас, и добавление их в метод JSNI решает все мои проблемы !!
jQuery .компенсировать() получит текущие координаты первого элемента или установит координаты каждого элемента в наборе согласованных элементов относительно документа.
По какой-то причине он не дает таких же результатов в IE по сравнению с другими браузерами. Я думаю, что в IE он задает положение относительно окна, поэтому, если вы прокрутите, вы получите разные результаты в IE по сравнению с другими
offset () сбивает с толку масштабированием, по крайней мере, в Android Chrome, поэтому бесполезен. stackoverflow.com/a/11396681/1691517 показывает устойчивый к масштабированию способ.
Это лучший код, который мне удалось создать (работает и в iframe, в отличие от смещения jQuery ()). Кажется, у webkit немного другое поведение.
На основе комментария meouw:
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.
$ .browser больше не доступен в последней версии jQuery.
к сожалению, даже с FF 24.4 приведенный выше код не работает, когда ширина границ существует как часть макета позиционирования.
Вы можете добавить два свойства к 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/
модификация Element.prototype обычно считается плохая идея. Это приводит к тому, что код очень сложно поддерживать. Кроме того, этот код не учитывает прокрутку.
Правильный подход - использовать element.getBoundingClientRect():
var rect = element.getBoundingClientRect();
console.info(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>');
А очень интересная статья о координатах JS. Эта статья нигде не упоминается о SO, она должна ..
Не работает ... это 8 пикселей по вертикали и горизонтали из-за поля 8 пикселей в теле. Решение Meouw работает отлично. Если хотите, у меня есть небольшой тест, чтобы продемонстрировать проблему.
@CpnCrunch: в каком браузере вы это видите? В моем тестировании код meouw и мой возвращают один и тот же результат независимо от поля элемента body.
Ломается как FF, так и хром. См. jsfiddle.net/D9VVy для ошибки (должны нарисовать два прямоугольника внутри друг друга). Рабочую версию (с использованием кода meouw) см. jsfiddle.net/Tn4FS
На самом деле, я думаю, это зависит от того, что вы действительно хотите получить. Вопрос немного двусмысленный. Ваш ответ правильный, если вам просто нужны координаты относительно области просмотра или относительно элемента body, но это не поможет вам в случае, когда вам нужна абсолютная позиция элемента (что, как я полагаю, это то, чего хочет большинство людей) . Ответ meouw тоже не дает вам этого, если вы не удалите биты «-scrollLeft» и «-scrollTop».
@CpnCrunch: теперь я понимаю, что вы имеете в виду; Я не понимал, что вы имеете в виду последнюю часть моего ответа. Когда у тела есть поле, его ограничивающая рамка будет смещена на это количество пикселей с каждой соответствующей стороны. В этом случае вам также придется вычесть вычисленный стиль полей из координат тела. Однако стоит отметить, что сброс CSS удаляет маржу из <body>.
Это решение elemRect.top - bodyRect.top и аналогично elemRect.left - bodyRect.left, к счастью, устойчиво к масштабированию. Смещение () jQuery дает разные результаты при масштабировании окна в Android Chrome. jQuery сдается в отношении offset(): размеры могут быть некорректными при увеличении страницы пользователем; браузеры не предоставляют API для обнаружения этого условия. Используя это решение для ответов, вам не нужен API для обнаружения условия масштабирования.
@DanDascalescu см. Вторую часть моего ответа, где позиция элемента сравнивается с позицией основного элемента.
Как мне получить расстояние до самого верха страницы?
document.scrollingElement был бы здесь так полезен ...!
@ RingØ +1 для pageXOffset и pageYOffset
@ RingØ - отличная статья, но часть «Получение координат документа», в которой используется только pageXOffset, pageYOffset не универсальна, так как не учитывает вложенные прокручиваемые области.
@ RingØ javascript.info - классный сайт, на нем много полезной информации.
element.getBoundingClientRect().top не возвращает правильное верхнее смещение в случае элемента position: fixed в iOS (iPhone 8), если он содержит сфокусированный элемент ввода и виртуальная клавиатура сдвинулась вверх. Например, если фактическое смещение от верха окна составляет 200 пикселей, он будет сообщать, что это 420 пикселей, где 220 пикселей - это высота виртуальной клавиатуры. Если вы установите position: absolute элемента и разместите его в том же положении, как если бы он был зафиксирован, то вы получите правильные 200 пикселей. Я не знаю решения этой проблемы.
Вау, это просто с другой планеты. Спасибо!
Это классическое решение.
Если вы используете jQuery, это может быть простое решение:
<script>
var el = $("#element");
var position = el.position();
console.info( "left: " + position.left + ", top: " + position.top );
</script>
Чтобы получить позицию относительно страницы эффективно и без использования рекурсивной функции: (также включает 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 делает этот ответ немного более правильным.
Просто подумал, что я тоже выкину это там.
Мне не удалось протестировать его в старых браузерах, но он работает в последней из лучших 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()};
};
Я успешно использовал решение Andy E для размещения модального окна bootstrap 2 в зависимости от того, на какую ссылку в строке таблицы нажимает пользователь. Это страница Tapestry 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, и я не мог понять, как добавить к нему всплывающее окно, которое я создавал, чтобы поместить его в область просмотра, потому что все дерево DOM взломано с несколькими заполнителями и неправильной разметкой. Мне нужно было использовать body.getBoundingClientRect (), а затем использовать его верхнюю часть в позиционировании. Спасибо.
Самый чистый подход, который я нашел, - это упрощенная версия техники, используемой 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;
var els = document.getElementsByTagName("div");
var docEl = document.documentElement;
for (var i = 0; i < els.length; i++) {
var rect = els[i].getBoundingClientRect();
var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;
els[i].innerHTML = "<b>" + rectLeft + ", " + rectTop + "</b>";
}div {
width: 100px;
height: 100px;
background-color: red;
border: 1px solid black;
}
#rel {
position: relative;
left: 10px;
top: 10px;
}
#abs {
position: absolute;
top: 250px;
left: 250px;
}<div id = "rel"></div>
<div id = "abs"></div>
<div></div>Поскольку разные браузеры по-разному отрисовывают границы, отступы, поля и т. д. Я написал небольшую функцию для извлечения верхней и левой позиции определенного элемента в каждом корневом элементе, который вы хотите в точном измерении:
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
Для возврата в левую позицию необходимо вернуть:
return offsetRect.left - rootRect.left;
Эта функция возвращает позицию элемента относительно всего документа (страницы):
function getOffset(el) {
const rect = el.getBoundingClientRect();
return {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY
};
}
Используя это, мы можем получить позицию X:
getOffset(element).left
... или положение Y:
getOffset(element).top
Только это решение работает для меня, когда элемент помещен в div, центрированный с использованием css top:50%, left:50%; transform:translate(-50%, -50%); ... отлично. Согласитесь с вопросом @ScottBiggs. Логично стремиться к простоте.
возможно, это не победитель, потому что он такой же, как и решение Andy E, но не работает в старых браузерах <IE9
getBoundingClientRect вызывает резкий скачок перерисовки в моих диаграммах производительности
Разве это не должно быть ";" после возвращения {...}?
Как правило, не рекомендуется повторно использовать переменные, но здесь действительно странно повторно использовать el, почему бы не var rect = ... или что-то в этом роде? это намного понятнее.
@tokland Я не думаю, что это «общее правило», хотя это особенность некоторых стилей программирования, таких как функциональное программирование. При этом я вижу, как это оптимизирует вышеизложенное. Вы можете передать суть? Рад рассмотреть возможность внесения изменений, направленных на дальнейшее улучшение. Спасибо.
@AdamGrant, я бы просто переименовал второй el, например в rect.
Вы должны определить rect с помощью var, let или const. В противном случае он определяется как window.rect.
@ hev1 Также можно использовать this, но const имеет смысл. Просто изменилось. Спасибо!
@AdamGrant Нет проблем.
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2) вернет среднюю позицию элемента
Аккуратный! @abhishake
Почему я получаю, что el is null, с этим и любым другим ответом здесь. Использование на codepen или попытки тоже .. плюс getBoundingClientRect () должен иметь хотя бы 1 параметр нет?
@RyanStone Не могли бы вы поделиться своей ручкой? Трудно поставить диагноз, ничего не видя.
Я сделал это так, чтобы он был перекрестно совместим со старыми браузерами.
// 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
После долгих исследований и испытаний, похоже, это сработало.
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 };
}
Я взял ответ @meouw, добавил в clientLeft, который позволяет использовать границу, а затем создал три версии:
getAbsoluteOffsetFromBody - аналогично @meouw, получает абсолютную позицию относительно тела или элемента html документа (в зависимости от режима причуд)
getAbsoluteOffsetFromGivenElement - возвращает абсолютную позицию относительно данного элемента (relativeEl). Обратите внимание, что данный элемент должен содержать элемент el, иначе он будет вести себя так же, как getAbsoluteOffsetFromBody. Это полезно, если у вас есть два элемента, содержащихся в другом (известном) элементе (возможно, несколько узлов в дереве узлов), и вы хотите сделать их одинаковыми.
getAbsoluteOffsetFromRelative - возвращает абсолютную позицию относительно первого родительского элемента с position: relative. Это похоже на 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 начальной загрузки, это мне очень помогло.
На всякий случай, если Meouw поменяет логин, ссылка для ответа: stackoverflow.com/a/442474/3654837. (Я не хочу натыкаться на эту старую ветку, так что да, я оставил комментарий)
Разница между маленьким и маленьким
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
К сожалению, это не работает для всех элементов, которые можно найти в современном HTML-документе. Например, встроенные элементы <svg> не имеют свойств offsetLeft, offsetTop и offsetParent.
Это просто DIV или IMG, а не SVG. Посмотреть "Посмотрите пример координат"? вы можете найти объект svg - это вызов позиции getOffsetRect, попытаться и зависеть от работы объекта.
Как насчет того, чтобы передать идентификатор элемента, и он вернет left или top, мы также можем объединить их:
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');
Хотя очень вероятно, что это будет потеряно в нижней части стольких ответов, лучшие решения здесь не работали для меня.
Насколько я мог судить, ни один из других ответов не помог бы.
Ситуация:
На странице HTML5 у меня было меню, которое представляло собой элемент навигации внутри заголовка (не заголовок THE, а заголовок в другом элементе).
Я хотел, чтобы навигация оставалась наверху после того, как пользователь прокручивает ее, но до этого заголовок располагался абсолютным позиционированием (так что я мог бы немного перекрыть что-то еще).
Приведенные выше решения никогда не вызывали изменений, потому что .offsetTop не собирался меняться, поскольку это был элемент с абсолютным позиционированием. Кроме того, свойство .scrollTop было просто вершиной самого верхнего элемента ... то есть 0 и всегда будет 0.
Любые тесты, которые я проводил с использованием этих двух (и то же самое с результатами getBoundingClientRect), не скажут мне, прокручивалась ли когда-либо верхняя часть панели навигации до верхней части просматриваемой страницы (опять же, как сообщалось в консоли, они просто оставались теми же числами при прокрутке произошел).
Решение
Решением для меня было использование
window.visualViewport.pageTop
Значение свойства pageTop отражает видимую часть экрана, что позволяет мне отслеживать, где находится элемент по отношению к границам видимой области.
Наверное, нет необходимости говорить, что каждый раз, когда я имею дело с прокруткой, я собираюсь использовать это решение, чтобы программно реагировать на движение прокручиваемых элементов.
Надеюсь, это поможет кому-то другому.
ВАЖНОЕ ПРИМЕЧАНИЕ: Похоже, что в настоящее время это работает в Chrome и Opera и определенно не в Firefox (6-2018). ... до тех пор, пока Firefox не будет поддерживать visualViewport, я рекомендую НЕ использовать этот метод (и я надеюсь, что они скоро сделают это ... он имеет гораздо больше смысла, чем остальные).
Обновлено:
Просто примечание относительно этого решения.
Хотя я все еще считаю то, что я обнаружил, очень ценным для ситуаций, в которых «... программно реагирует на движение прокручиваемых элементов». применимо. Лучшим решением возникшей у меня проблемы было использование CSS для установки позиция: липкая в элементе. Используя липкий, вы можете оставить элемент наверху без использования javascript (ПРИМЕЧАНИЕ: иногда это не будет работать так же эффективно, как изменение элемента на фиксированный, но для большинства применений липкий подход, вероятно, будет лучше)
ОБНОВЛЕНИЕ01:
Итак, я понял, что для другой страницы у меня было требование, когда мне нужно было определять положение элемента в умеренно сложной настройке прокрутки (параллакс плюс элементы, которые прокручиваются как часть сообщения).
В этом сценарии я понял, что следующее дает значение, которое я использовал, чтобы определить, когда что-то делать:
let bodyElement = document.getElementsByTagName('body')[0];
let elementToTrack = bodyElement.querySelector('.trackme');
trackedObjPos = elementToTrack.getBoundingClientRect().top;
if (trackedObjPos > 264)
{
bodyElement.style.cssText = '';
}
Надеюсь, этот ответ теперь более полезен.
очень вероятно, что это будет первым из многих ответов, когда вы нажмете активный, чтобы отсортировать ответы
@lucchi: D ну, я полагаю, я мог бы удалить текст @ вверху ... хотя я только что наткнулся на это снова и понял, что нашел лучшее решение для моей собственной проблемы ... хотя мой ответ скорее сноска к более полным ответам. Я подозреваю, что мои требования, возможно, были не настолько распространены, что другие ответы не работали для меня?
В любом случае, я ценю ваш ответ, я просто хотел сказать вам, что любой желающий будет знать, что вы написали что-то новое. Ты не одинок....
Get position of div in respect to left and Top
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, я уважаю ваше решение, но я уже объяснял в тексте, что «нижний и правый код не тестируется.». Кроме того, я очень скоро обновлю свой код.
Я думаю, что это el.offsetTop и el.offsetLeft (OP ничего не говорит о jQuery ... Я не уверен, почему в вашем ответе также используется jQuery ...)
Если вы хотите, чтобы это было сделано только в javascript, вот несколько один лайнер с использованием getBoundingClientRect()
window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y
window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X
Первая строка вернет offsetTop, скажем, Y относительно документа.
Вторая строка вернет offsetLeft, скажем, X относительно документа.
getBoundingClientRect() - это функция javascript, которая возвращает положение элемента относительно области просмотра окна.
Это должно быть решением. Здесь нет длинного кода vs, он понятен и очень точен!
что, если элемент находится внутри прокручиваемого элемента? Единственный способ сделать это - суммировать offsetTop всех родительских элементов, как предлагают другие ответы
Как утверждает Дмитрий, это неверно и очень некорректно. У него не должно быть столько голосов "за", как сейчас. Он ВСЕГДА также будет в прокручиваемом элементе, потому что сам документ можно прокручивать. Другими словами, если весь документ не умещается во вьюпорте, он всегда будет неверным, если пользователь вообще прокрутил главное окно.
это тоже было бы моим любимым решением, но будьте осторожны: он запускает перерисовку каждый раз, когда вы это делаете. (если делать это слишком часто, это приведет к медленной анимации)
Чтобы получить общее смещение элемента, вы можете рекурсивно суммировать все родительские смещения:
function getParentOffsets(el): number {
if (el.offsetParent) {
return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
return 0;
}
}
с помощью этой служебной функции общее смещение сверху элемента dom равно:
el.offsetTop + getParentOffsets(el);
Этот ответ выглядит так, как хотелось бы, за исключением того, что я получаю сообщение об ошибке «Uncaught ReferenceError: getParentOffset is not defined». Отсутствует буква "s", не так ли? Поэтому я изменил строку возврата функции, добавив букву «s» в «getParentOffset». Сейчас ошибок нет, но меня беспокоит, зная, что это была ошибка ...
/**
*
* @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;
}
Это просто, как две строчки в JS:
var elem = document.getElementById("id");
alert(elem.getBoundingClientRect());
Этот ответ неполный и ничего не добавляет к предыдущим ответам.
Я использовал эти 7 строк кода, который работает во всех браузерах с несоответствиями в ie5,6,7 (я не помню, чтобы у меня были какие-либо пробоемы ... может быть тип документа) ... quirksmode.org/js/findpos.html, и я использовал его как много на столько лет. Может быть, кто-нибудь может указать на недостатки, если таковые имеются.