Я хочу знать, как получить положение X и Y элементов HTML, таких как img
и div
в JavaScript, относительно окна браузера.
Я хочу знать, как получить положение X и Y элементов HTML, таких как img
и div
в JavaScript, относительно окна браузера.
Ответы:
Правильный подход заключается в использовании 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>');
<body>
.
element.getBoundingClientRect().top
не возвращает правильное верхнее смещение в случае position: fixed
элемента в iOS (iPhone 8), если он содержит сфокусированный элемент ввода и виртуальная клавиатура сдвинулась вверх. Например, если фактическое смещение от вершины окна составляет 200px, оно сообщит об этом как 420px, где 220px - высота виртуальной клавиатуры. Если вы установите элемент position: absolute
и разместите его в том же положении, как если бы он был зафиксирован, тогда вы получите правильные 200px. Я не знаю решения этого.
Библиотеки идут на все, чтобы получить точные смещения для элемента.
Вот простая функция, которая делает работу при любых обстоятельствах, которые я пробовал.
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
};
}
Используя это мы можем позвонить
getOffset(element).left
или
getOffset(element).top
div
центр с использованием css top:50%, left:50%; transform:translate(-50%, -50%);
... отлично. Согласитесь с вопросом @ScottBiggs. Логично стремиться к простоте.
rect
используя var
, let
или const
. В противном случае он определяется как window.rect
.
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)
вернет среднее положение элемента
Если вы хотите, чтобы это было сделано только в JavaScript , вот некоторые из них, используяgetBoundingClientRect()
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;
Вот демонстрация, сравнивающая результаты с jQuery offset().top
и .left
: http://jsfiddle.net/ThinkingStiff/3G7EZ/
Element.prototype
вообще считается плохой идеей . Это приводит к очень сложному обслуживанию кода. Кроме того, этот код не учитывает прокрутку.
Чтобы получить позицию относительно страницы эффективно и без использования рекурсивной функции: (также включает 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;
Как насчет чего-то подобного, передав 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');
Возможно, вам лучше будет использовать JavaScript-фреймворк, в котором есть функции для возврата такой информации (и многое другое!) Независимо от браузера. Вот несколько из них:
С помощью этих структур вы можете сделать что-то вроде:
$('id-of-img').top
получить координату Y-пикселя изображения.
jQuery .offset () получит текущие координаты первого элемента или установит координаты каждого элемента в наборе совпадающих элементов относительно документа.
Я взял ответ @ 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, который должен быть нормальным, если браузеры ведут себя хорошо , но все остальное не проверял.
при использовании jQuery плагин размеров превосходен и позволяет вам точно указать, что вы хотите.
например
Относительная позиция, абсолютная позиция, абсолютная позиция без заполнения, с заполнением ...
Это продолжается, скажем так, с этим можно многое сделать.
Плюс преимущество использования jQuery - это легкий размер файла и простота использования, после чего вы не вернетесь к JavaScript без него.
Это лучший код, который мне удалось создать (работает также в 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, это может быть простое решение:
<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
свойства.
DIV
или IMG
нет SVG
. Посмотреть "Посмотреть пример координат"? Вы можете найти объект svg в позиции вызова getOffsetRect , попробуйте и зависит от работы объекта.
Самый чистый подход, который я нашел, - это упрощенная версия техники, используемой 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;
Хотя это очень вероятно будет потеряно из-за большого количества ответов, лучшие решения здесь не работают для меня.
Насколько я мог сказать, ни один из других ответов не помог бы.
Ситуация :
на странице 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 = '';
}
Надеюсь, что этот ответ более полезен сейчас.
Я сделал это так, чтобы он был совместим со старыми браузерами.
// 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 getParentOffsets(el): number {
if (el.offsetParent) {
return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
return 0;
}
}
с помощью этой вспомогательной функции общее верхнее смещение элемента dom:
el.offsetTop + getParentOffsets(el);
/**
*
* @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 за ответ , это всего лишь еще одна версия.
Я успешно использовал решение Энди Э. для позиционирования модуса начальной загрузки 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');");
}
});
}
Надеюсь, это поможет кому-то, этот пост помог.
После долгих исследований и испытаний это, кажется, работает
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 };
}
Просто подумал, что я тоже это выброшу.
Я не смог протестировать его в старых браузерах, но он работает в последней версии топ-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()};
};
Так как разные браузеры по-разному отображают границы, отступы, поля и т. Д. Я написал небольшую функцию, чтобы получить верхнюю и левую позиции определенного элемента в каждом корневом элементе, который вы хотите в точном измерении:
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
Для восстановления левой позиции вы должны вернуть:
return offsetRect.left - rootRect.left;
Получить положение 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
el.offsetTop
и el.offsetLeft
(ОП ничего не говорит о jQuery ... Я не уверен, почему ваш ответ также использует jQuery ...)