Я хочу знать, как получить 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>');
Библиотеки идут до некоторой длины, чтобы получить точные смещения для элемента.
здесь простая функция, которая выполняет работу в любых обстоятельствах, которые я пробовал.
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) {
el = el.getBoundingClientRect();
return {
left: el.left + window.scrollX,
top: el.top + window.scrollY
}
}
Используя это, мы можем назвать
getOffset(element).left
или
getOffset(element).top
div
, центрированный с помощью css top:50%, left:50%; transform:translate(-50%, -50%);
... отлично. Согласитесь с вопросом @ScottBiggs. Логично стремиться к простоте.
Вы можете добавить два свойства в 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
обычно считается плохой идеей . Это приводит к очень сложному обслуживанию кода. Также этот код не учитывает прокрутку.
Если страница включает в себя - по крайней мере, любую "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];
};
Чтобы получить позицию относительно страницы эффективно и без использования рекурсивной функции: (также включает IE)
var element = document.getElementById('elementId'); //replace elementId with your element 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;
Элементы HTML в большинстве браузеров будут иметь: -
offsetLeft
offsetTop
Они определяют положение элемента относительно его ближайшего родителя, у которого есть макет. К этому родительскому объекту часто можно обращаться через свойство offsetParent.
IE и FF3 имеют
clientLeft
clientTop
Эти свойства менее распространены, они определяют позицию элементов с клиентской областью его родителей (заполненная область является частью клиентской области, но граница и маржа не являются).
Вам может быть лучше, если использовать фреймворк JavaScript, который имеет функции для возврата такой информации (и многое другое!) независимо от браузера. Вот несколько:
В этих рамках вы можете сделать что-то вроде:
$('id-of-img').top
для получения координаты y-пикселя изображения.
jQuery . offset() получит текущие координаты первого элемента или задает координаты каждого элемента в наборе согласованных элементов относительно документа.
Как о чем-то подобном, передавая идентификатор элемента, и он вернет левый или верхний, мы можем их объединить:
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');
Я принял @meouw ответ, добавленный в clientLeft, который позволяет использовать границу, а затем создал три версии:
getAbsoluteOffsetFromBody - аналогично @meouw, это получает абсолютную позицию относительно элемента body или html документа (в зависимости от режима quirks)
getAbsoluteOffsetFromGivenElement - возвращает абсолютную позицию относительно данного элемента (relativeEl). Обратите внимание, что данный элемент должен содержать элемент el, иначе он будет вести себя так же, как getAbsoluteOffsetFromBody. Это полезно, если у вас есть два элемента, содержащиеся в другом (известном) элементе (необязательно несколько узлов вверх по дереву node) и хотите сделать их одинаковыми.
getAbsoluteOffsetFromRelative - возвращает абсолютную позицию относительно первого родительского элемента с положением: 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, размерный плагин отличный и позволяет вам точно указать, что вы хотите.
например.
Относительное положение, абсолютное положение, абсолютное положение без заполнения, с заполнением...
Продолжайте, давайте просто скажем, что вы можете с ним многое сделать.
Кроме того, бонус использования jQuery - это легкий размер файла и простота использования, после этого вы не вернетесь к JavaScript без него.
Если вы используете jQuery, это может быть простое решение:
<script>
var el = $("#element");
var position = el.position();
console.log( "left: " + position.left + ", top: " + position.top );
</script>
Это лучший код, который мне удалось создать (работает и в iframe, в отличие от jQuery offset()). Кажется, у 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
.
Разница между маленькими и маленькими
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
для настройки положения прокрутки, а также таких вещей, как margin на 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>
Я сделал это так, чтобы он был перекрестно совместим со старыми браузерами.
// For really old browser 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 для размещения бутстрапа 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');");
}
});
}
Надеюсь, что это поможет кому-то, этот пост помог.
Просто подумал, что я тоже выброшу это.
Я не смог проверить его в старых браузерах, но он работает в последней версии 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 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 };
}
Хотя это, скорее всего, будет потеряно в основе стольких ответов, верхние решения здесь не работают для меня.
Насколько я мог сказать, ни один из других ответов не помог бы.
<Б > Ситуация:
На странице HTML5 у меня было меню, которое было элементом навигации внутри заголовка (не заголовком, а заголовком в другом элементе).
Я хотел, чтобы навигационная система придерживалась вершины, как только пользователь прокручивал ее, но до этого заголовок был абсолютно позиционирован (так что я мог бы немного наложить что-то еще).
Вышеупомянутые решения никогда не приводили к изменению, потому что .offsetTop не собирался меняться, поскольку это был элемент с абсолютным позиционированием. Кроме того, свойство .scrollTop было просто вершиной верхнего элемента..., то есть 0 и всегда было бы 0.
Любые тесты, которые я выполнил, используя эти два (и то же самое с результатами getBoundingClientRect), не сказали бы мне, что верхняя часть навигационной панели когда-либо прокручивалась до верхней части просматриваемой страницы (опять же, как сообщалось на консоли, они просто оставались одинаковыми числами при прокрутке произошло).
Решение
Решение для меня использовало
window.visualViewport.pageTop
Значение свойства pageTop отражает видимый раздел экрана, поэтому позволяет отслеживать, где элемент относится к границам области просмотра.
Возможно, нет необходимости говорить, что в любое время, когда я занимаюсь прокруткой, я ожидаю использовать это решение для программного реагирования на перемещение прокручиваемых элементов.
Надеюсь, это поможет кому-то другому.
Поскольку разные браузеры - это визуализация границы, отступов, полей и т.д. по-разному. Я написал небольшую функцию для получения верхней и левой позиций определенного элемента в каждом корневом элементе, который вы хотите в точном размере:
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
Для получения левой позиции вы должны вернуть:
return offsetRect.left - rootRect.left;