Я хочу знати, як отримати 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 Views . Усі інші браузери його прийняли давно .
Деякі браузери також повертають властивості висоти та ширини, хоча це нестандартно. Якщо ви турбуєтесь про сумісність попереднього браузера, перегляньте редакції цієї відповіді, щоб оптимізувати її приниження.
Повернені значення 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), якщо він містить сфокусований вхідний елемент і віртуальна клавіатура зісковзнула вгору. Наприклад, якщо фактичне зміщення у верхній частині вікна дорівнює 200 пікселів, воно повідомляє про це як 420 пікселів, де 220 пікселів - висота віртуальної клавіатури. Якщо встановити елементи елемента 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" за межі поточних сторінок. Для того, щоб знайти точну позицію, вам потрібно обробити як зміщення, так і батьківські та батьківські.
Спробуйте вказаний нижче код (він перевіряється на 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;
Як щодо чогось подібного, передаючи ідентифікатор елемента, і він поверне лівий або верхній, ми також можемо їх поєднати:
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's, це отримує абсолютне положення відносно елемента тіла або html документа (залежно від режиму примх)
getAbsoluteOffsetFromGivenElement - повертає абсолютне положення відносно даного елемента (RelaEl). Зауважте, що даний елемент повинен містити елемент el, інакше це буде поводитись так само, як getAbsoluteOffsetFromBody. Це корисно, якщо у вас є два елементи, що містяться в іншому (відомому) елементі (необов'язково кілька вузлів вгору по дереву вузла) і хочете зробити їх однаковими.
getAbsoluteOffsetFromRelative - повертає абсолютне положення відносно першого батьківського елемента з позицією: відносно. Це схоже на 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 ()). Здається, веб-сайт має дещо іншу поведінку.
На основі коментаря 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, це може бути простим рішенням:
<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/coordinate
<svg>
елементи, наприклад, не мають offsetLeft
, offsetTop
і offsetParent
властивості.
DIV
чи IMG
ні SVG
. Переглянути "Подивіться приклади координат"? Ви можете знайти об'єкт svg - це виклик позиції getOffsetRect , спробуйте залежати від роботи об'єкта.
Найчистіший підхід, який я знайшов, - це спрощена версія методики, що використовується jQuery's 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 для встановлення позиції: липкийна стихію. Використовуючи липкий, ви можете залишити елемент у верхній частині, не використовуючи JavaScript (ПРИМІТКА. Можливо, це не буде настільки ефективно, як зміна елемента на фіксований, але для більшості використовує клейкий підхід, ймовірно, буде вище)
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/coordinate
Щоб отримати загальний зсув елемента, ви можете рекурсивно підсумовувати всі батьківські зміщення:
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;
Отримайте позицію діва щодо ліворуч та верху
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 або ...)