it-swarm.com.ru

Получить позицию (X, Y) HTML-элемента

Я хочу знать, как получить положение X и Y таких элементов HTML, как img и div в JavaScript.

1297
monaung

Правильный подход заключается в использовании 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>');
1568
Andy E

Библиотеки идут на все, чтобы получить точные смещения для элемента.
Вот простая функция, которая делает работу при любых обстоятельствах, которые я пробовал.

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; 
297
meouw

Это сработало для меня (модифицировано из ответов с наибольшим количеством голосов):

function getOffset(el) {
  const rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.scrollX,
    top: rect.top + window.scrollY
  };
}

Используя это мы можем позвонить

getOffset(element).left

или же

getOffset(element).top
200
Adam Grant

Элементы HTML в большинстве браузеров будут иметь: -

offsetLeft
offsetTop

Они определяют положение элемента относительно его ближайшего родителя, который имеет макет. К этому родителю часто можно получить доступ со свойством offsetParent.

IE и FF3 имеют

clientLeft
clientTop

Эти свойства менее распространены, они задают положение элементов в родительской клиентской области (заполненная область является частью клиентской области, а границы и поля - нет).

35
AnthonyWJones

Если страница содержит, по крайней мере, какой-либо "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];
};

34
Refik Ayata

Вы можете добавить два свойства в 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/

32
ThinkingStiff

Если вы хотите, чтобы это было сделано только в javascript , вот несколько однострочников используя getBoundingClientRect()

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

Первая строка вернет offsetLeft скажем X относительно документа.

Вторая строка вернет offsetTop скажем Y относительно документа.

getBoundingClientRect() - это функция javascript, которая возвращает позицию элемента относительно окна просмотра окна.

25
Asif J

Чтобы получить позицию относительно страницы эффективно и без использования рекурсивной функции: (также включает в себя 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;
21
Abdul Rahim Haddad

Как насчет чего-то подобного, передав 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');

или ) найти слева и сверху вместе

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');
19
Alireza

Возможно, вам лучше будет использовать JavaScript-фреймворк, в котором есть функции для возврата такой информации (и многое другое!) Независимо от браузера. Вот несколько из них:

С помощью этих структур вы можете сделать что-то вроде: $('id-of-img').top, чтобы получить координату Y-пикселя изображения.

16
Shalom Craimer

jQuery . offset () получит текущие координаты первого элемента или установит координаты каждого элемента в наборе соответствующих элементов относительно документа.

14
akauppi

Я взял ответ @ 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 что должно быть хорошо, если браузеры ведут себя хорошо, а остальные вообще не тестировали.

10
James Carlyle-Clarke

если вы используете jQuery, плагин измерения отлично подходит и позволяет вам точно указать, что вы хотите.

например.

Относительная позиция, абсолютная позиция, абсолютная позиция без заполнения, с заполнением ...

Это продолжается, скажем так, с этим можно многое сделать.

Плюс преимущество использования jQuery - это легкий размер файла и простота использования, после чего вы не вернетесь к JavaScript без него.

8
John_

Если вы используете jQuery, это может быть простое решение:

<script>
  var el = $("#element");
  var position = el.position();
  console.log( "left: " + position.left + ", top: " + position.top );
</script>
7
Adam Boostani

Это лучший код, который мне удалось создать (работает также в 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 };
}
7
Ron Reiter

Разница между маленьким и маленьким

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

7
KingRider

Самый чистый подход, который я нашел, - это упрощенная версия техники, используемой offset в jQuery. Подобно некоторым другим ответам, он начинается с 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>
6
James Montagne

Я сделал это так, чтобы он был совместим со старыми браузерами.

// 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

5
Bojan Kseneman

Хотя это очень вероятно будет потеряно из-за большого количества ответов, лучшие решения здесь не работают для меня.
Насколько я мог судить, ни один из других ответов не помог бы.

Ситуация:
На странице HTML5 у меня было меню, которое было элементом nav внутри заголовка (не заголовок THE, а заголовок в другом элементе).
Я хотел, чтобы навигация прилипала к вершине, когда пользователь прокручивал ее, но до этого заголовок располагался в абсолютном положении (поэтому я мог немного наложить его на что-то другое).
Приведенные выше решения никогда не вызывали изменений, потому что .offsetTop не собирался меняться, поскольку это был элемент с абсолютным позиционированием. Кроме того, свойство .scrollTop было просто вершиной самого верхнего элемента ... то есть 0 и всегда будет 0.
Любые тесты, которые я выполнял, используя эти два (и то же самое с результатами getBoundingClientRect), не сообщали бы мне, прокручивалась ли верхняя часть панели навигации до верхней части просматриваемой страницы (опять же, как сообщалось в консоли, они просто оставались одни и те же цифры при прокрутке происходили).

Решение
Решением для меня было использование

window.visualViewport.pageTop

Значение свойства pageTop отражает видимую часть экрана, поэтому я могу отслеживать, где находится элемент относительно границ видимой области.

Вероятно, нет необходимости говорить, что всякий раз, когда я имею дело с прокруткой, я ожидаю использовать это решение для программной реакции на движение прокручиваемых элементов.
Надеюсь, это поможет кому-то еще.
ВАЖНОЕ ПРИМЕЧАНИЕ: Похоже, что это работает в Chrome и ​​Opera в настоящее время и определенно не в Firefox (6-2018) ... пока Firefox не поддерживает visualViewport, я рекомендую НЕ использовать этот метод (и я надеюсь, что они скоро это сделают ... это имеет гораздо больший смысл, чем остальные).


[. .____] ОБНОВЛЕНИЕ:
Просто примечание относительно этого решения.
Хотя я все еще нахожу, что обнаружил, что это очень ценно для ситуаций, в которых "... программно реагирует на движение прокручиваемых элементов". применимо. Лучшим решением проблемы, с которой я столкнулся, было использование CSS для установки position: 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 = '';
  }

Надеюсь, что этот ответ более полезен сейчас.

4
MER

Я успешно использовал решение Энди Э. для позиционирования модального 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');");
        }
    });
}

Надеюсь, это поможет кому-то, этот пост помог.

2
Mark Espinoza

Чтобы получить общее смещение элемента, вы можете рекурсивно суммировать все родительские смещения:

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

с помощью этой вспомогательной функции общее верхнее смещение элемента dom:

el.offsetTop + getParentOffsets(el);
2
Kevin K.

После долгих исследований и испытаний это, кажется, работает

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

1
kernowcode

Просто подумал, что я тоже это выброшу.
Я не смог протестировать его в старых браузерах, но он работает в последней версии топ-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()};
};
1
Duncan

Получить положение 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 
0
Vishal

Так как разные браузеры по-разному отображают границы, отступы, поля и т.д. Я написал небольшую функцию, чтобы получить верхнюю и левую позиции определенного элемента в каждом корневом элементе, который вы хотите в точном измерении:

function getTop(root, offset) {
    var rootRect = root.getBoundingClientRect();
    var offsetRect = offset.getBoundingClientRect();
    return offsetRect.top - rootRect.top;
}

Для восстановления левой позиции вы должны вернуть:

    return offsetRect.left - rootRect.left;
0
samadadi