Я хочу знать, как получить положение X и Y элементов HTML, таких как img
и div
, в JavaScript относительно окна браузера.
Получить позицию (X, Y) элемента HTML относительно окна браузера
Ответы (27)
Правильный подход - использовать 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>');
Библиотеки идут на все, чтобы получить точные смещения для элемента.
вот простая функция, которая выполняет свою работу в любых обстоятельствах, которые я пробовал.
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;
Эта функция возвращает позицию элемента относительно всего документа (страницы):
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
Версия TypeScript:
export type ElementOffset = {
left: number;
top: number
};
/**
* Returns an element's position relative to the whole document (page).
*
* If the element does not exist, returns O/O (top-left window corner).
*
* @example getOffset(document.getElementById('#element'));
*
* @param el
* @see https://stackoverflow.com/a/28222246/2391795
*/
export const getElementOffset = (el: Element | null): ElementOffset => {
const rect = el?.getBoundingClientRect();
return {
left: (rect?.left || 0) + window?.scrollX,
top: (rect?.top || 0) + window?.scrollY,
};
};
export default getElementOffset;
Если вы хотите, чтобы это было сделано только в javascript, вот несколько однострочников с использованием _ 1_
window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y
window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X
Первая строка вернет offsetTop
, скажем, Y относительно документа. Вторая строка вернет offsetLeft
, скажем, X относительно документа.
getBoundingClientRect()
- это функция JavaScript, которая возвращает положение элемента относительно области просмотра. окна.
Элементы HTML в большинстве браузеров будут иметь: -
offsetLeft
offsetTop
Они определяют положение элемента относительно его ближайшего родителя, у которого есть макет. К этому родительскому элементу часто можно получить доступ через свойство offsetParent.
IE и FF3 имеют
clientLeft
clientTop
Эти свойства менее распространены, они определяют положение элемента вместе с его родительской клиентской областью (заполненная область является частью клиентской области, а граница и поля - нет).
Если страница включает - по крайней мере - любой «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];
};
Вы можете добавить два свойства к 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;
Вот демонстрация, сравнивающая результаты с offset().top
и .left
jQuery: http://jsfiddle.net/ThinkingStiff/3G7EZ/ а>
Element.prototype
обычно считается плохой идеей. Это приводит к тому, что код очень сложно поддерживать. Кроме того, этот код не учитывает прокрутку.
- person Jared Forsyth; 23.06.2015
Чтобы получить позицию относительно страницы эффективно и без использования рекурсивной функции: (также включает 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;
Как насчет того, чтобы передать идентификатор элемента, и он вернет 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');
jQuery .offset () получит текущие координаты первого элемента или установит координаты каждого элемента в наборе совпадающих элементов относительно документа.
Возможно, вам будет удобнее использовать фреймворк JavaScript, который имеет функции для возврата такой информации (и многого другого!) Независимо от браузера. Вот несколько:
С помощью этих фреймворков вы можете сделать что-то вроде: $('id-of-img').top
, чтобы получить координату y-пикселя изображения.
/**
*
* @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 за ответ, это всего лишь другая версия.
Я взял ответ @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, который должен работать, если предположить, что браузеры работают, но не тестировал остальное.
при использовании jQuery отлично подходит подключаемый модуль размеров, который позволяет указать именно то, что вы хотите.
e.g.
Относительное положение, абсолютное положение, абсолютное положение без заполнения, с заполнением ...
Это продолжается, давайте просто скажем, что вы можете многое с этим сделать.
Плюс к этому бонус от использования jQuery - это легкий размер файла и простота использования, вы не вернетесь к JavaScript без него впоследствии.
Если вы используете jQuery, это может быть простое решение:
<script>
var el = $("#element");
var position = el.position();
console.log( "left: " + position.left + ", top: " + position.top );
</script>
Разница между маленьким и маленьким
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
<svg>
не имеют свойств offsetLeft
, offsetTop
и offsetParent
.
- person Jonathan Eunice; 19.10.2016
DIV
или IMG
, а не SVG
. Посмотреть Посмотрите пример координат? вы можете найти объект svg в вызове позиции getOffsetRect, попробовать и получить зависимость от объекта.
- person KingRider; 19.10.2016
Самый чистый подход, который я нашел, - это упрощенная версия техники, используемой 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>
Это лучший код, который мне удалось создать (работает и в 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
.
- person S P; 07.03.2012
Хотя это, скорее всего, будет потеряно в нижней части стольких ответов, лучшие решения здесь не работали для меня.
Насколько я мог сказать, ни один из других ответов не помог бы.
Ситуация:
На странице HTML5 у меня было меню, которое представляло собой элемент навигации внутри заголовка (не заголовок THE, а заголовок в другом элементе).
I хотел, чтобы навигация оставалась наверху, когда пользователь прокручивает ее, но до этого заголовок был позиционирован абсолютно (так что я мог немного перекрыть что-то еще).
Приведенные выше решения никогда не вызывали изменения, потому что .offsetTop был не изменится, так как это был элемент с абсолютной позицией. Кроме того, свойство .scrollTop было просто вершиной самого верхнего элемента ... то есть 0 и всегда будет 0.
Любые тесты, которые я проводил с использованием этих двух (и то же самое с результатами getBoundingClientRect), не скажут мне, если верхняя часть панели навигации когда-либо прокручивалась до верхней части просматриваемой страницы (опять же, как сообщается в консоли, они просто оставались теми же номерами во время прокрутки).
Решение
Для меня решение использовало
window.visualViewport.pageTop
Значение свойства pageTop отражает видимую часть экрана, что позволяет мне отслеживать, где находится элемент по отношению к границам видимой области.
Наверное, нет необходимости говорить, что каждый раз, когда я имею дело с прокруткой, я собираюсь использовать это решение, чтобы программно реагировать на движение прокручиваемых элементов.
Надеюсь, это поможет кому-то другому.
ВАЖНОЕ ПРИМЕЧАНИЕ: Кажется, это работает в Chrome и Opera. в настоящее время и определенно не в Firefox (6-2018) ... пока Firefox не поддерживает visualViewport, я рекомендую НЕ использовать этот метод (и я надеюсь, что они скоро сделают это ... он имеет гораздо больше смысла, чем остальные).
ОБНОВЛЕНИЕ:
Обратите внимание на это решение.
Хотя я все еще считаю то, что я обнаружил, очень ценным для ситуаций, в которых «... программно реагируют на движение прокручиваемых элементов». применимо. Лучшим решением возникшей у меня проблемы было использование CSS для установки position: sticky на элементе. Используя липкий, вы можете оставить элемент наверху без использования javascript (ПРИМЕЧАНИЕ: иногда это не сработает так же эффективно, как изменение элемента на фиксированный, но для большинства применений липкий подход, вероятно, будет лучше)
UPDATE01:
Итак, я понял, что для другой страницы у меня было требование, когда мне нужно было определять положение элемента в умеренно сложной настройке прокрутки (параллакс плюс элементы, которые прокручиваются как часть сообщение). В этом сценарии я понял, что следующее дает значение, которое я использовал, чтобы определить, когда что-то делать:
let bodyElement = document.getElementsByTagName('body')[0];
let elementToTrack = bodyElement.querySelector('.trackme');
trackedObjPos = elementToTrack.getBoundingClientRect().top;
if(trackedObjPos > 264)
{
bodyElement.style.cssText = '';
}
Надеюсь, этот ответ теперь более полезен.
Чтобы получить общее смещение элемента, вы можете рекурсивно суммировать все родительские смещения:
function getParentOffsets(el): number {
if (el.offsetParent) {
return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
return 0;
}
}
с этой служебной функцией общее смещение сверху элемента dom равно:
el.offsetTop + getParentOffsets(el);
Я сделал это так, чтобы он был перекрестно совместим со старыми браузерами.
// 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
Я успешно использовал решение 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>
The link in the loop:
<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');");
}
});
}
Надеюсь, это кому-то поможет, этот пост помог.
После долгих исследований и испытаний, похоже, это сработало.
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
Просто подумал, что я тоже выкину это там.
Мне не удалось протестировать его в старых браузерах, но он работает в последней из лучших 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()};
};
Это просто, как две строчки в JS:
var elem = document.getElementById("id");
alert(elem.getBoundingClientRect());
Поскольку разные браузеры по-разному отрисовывают границы, отступы, поля и т. Д. Я написал небольшую функцию для извлечения верхней и левой позиции определенного элемента в каждом корневом элементе, который вы хотите в точном измерении:
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
Для возврата в левую позицию необходимо вернуть:
return offsetRect.left - rootRect.left;
Получить позицию div относительно left и 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
el.offsetTop
и el.offsetLeft
(OP ничего не говорит о jQuery ... Я не уверен, почему в вашем ответе также используется jQuery ...)
- person mesqueeb; 10.07.2018