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

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

Я использовал эти 7 строк кода, который работает во всех браузерах с несоответствиями в ie5,6,7 (я не помню, чтобы у меня были какие-либо пробоемы ... может быть тип документа) ... quirksmode.org/js/findpos.html, и я использовал его как много на столько лет. Может быть, кто-нибудь может указать на недостатки, если таковые имеются.

Jayapal Chandran 02.04.2015 18:27

@AnthonyWJones, я полагаю, вам нужно было педантичное удовольствие, но очевидно, как всегда, когда не указано иное, что OP относится к наиболее общему случаю или относится к координатам окна браузера.

Motes 26.05.2015 23:29

Ответ @ AndyE - явный победитель - не могли бы вы отметить принятый ответ, чтобы другим не пришлось читать 10 других ответов, чтобы добраться до него?

mindplay.dk 16.03.2016 18:14

Здравствуйте, мистер Грег. Можете ли вы решить эту мою проблему .. Я только что опубликовал свою ссылку. Нажмите ее один раз stackoverflow.com/questions/41743667/…

Lavaraju 23.01.2017 10:22

@Mote, нет, это не так уж и очевидно. Оставьте в стороне умозаключения, субъективность и ложные аксиомы. Это может быть относительно области просмотра или верхней части страницы (также известный как document.documentElement).

Andre Figueiredo 22.10.2017 05:27

Использование по умолчанию наиболее общего - это не вывод, это логическая последовательность, так что это будет относиться к окну или «верх страницы» может быть термином, как вы его выразили. В теории игр это кодифицировано как понятие, называемое точкой Шеллинга. Обязательно укажите, когда вы не имеете в виду самый общий случай.

Motes 22.10.2017 21:45

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

Andre Figueiredo 22.01.2019 23:22
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1 780
7
1 634 437
27

Ответы 27

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

offsetLeft
offsetTop

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

IE и FF3 имеют

clientLeft
clientTop

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

как это ответить на вопрос, который должен получить позицию элемента относительно окна браузера, а не только родительского элемента?

Prime 16.12.2020 21:59

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

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

Вы знаете, чем отличаются реализации? Используют ли библиотеки функции, похожие на перечисленные выше?

Costa 27.03.2013 10:16

@Costa Все они используют такие функции, хотя эта область постоянно развивается, поскольку разные браузеры по-разному соответствуют спецификации. Большая часть кода связана с «исправлением» того, что идет не так. Вам действительно стоит посмотреть исходный код.

Shalom Craimer 27.03.2013 21:38

Я пытался сделать именно это и нашел это очень полезным: james.padolsey.com/jquery У меня была странная проблема с исходным кодом библиотеки, каждый раз, когда я пытаюсь отформатировать его с помощью плагина beautifier или текстового редактора, я все равно получаю код javascript на две строчки.

Costa 27.03.2013 21:49

@scraimer: jQuery и YUI - это НЕ рамки !!! Это библиотеки! Это не одно и то же. Цитирование jquery.com: «jQuery - это быстрый, небольшой и многофункциональный JavaScript библиотека». Цитирование yuilibrary.com (вы также можете увидеть "волшебное" слово в URL ...): «YUI - это бесплатный JavaScript и CSS библиотека с открытым исходным кодом для создания полнофункциональных интерактивных веб-приложений».

Sk8erPeter 09.05.2013 15:34

Значит, вы должны использовать огромные библиотеки только для этой простой задачи? Не обязательно. Я ненавижу то, что каждый раз, когда я хочу что-то сделать с js, я получаю эти решения jQuery. jQuery - это не JS!

Opptatt Jobber 11.10.2013 23:14

@OpptattJobber Я согласен ... JQuery - это не javascript. Он полагается на Javascript, но это совершенно другой язык программирования.

Nick Manning 27.03.2014 04:31

@NickManning Это не новый язык, это уровень абстракции для DOM, который избавляет от необходимости писать обходные пути совместимости и производительности непосредственно в ваш код. Если вы не используете jQuery, вам в любом случае следует использовать какой-то уровень абстракции.

ginman 04.04.2014 19:01

jQuery написан на javascript, так как же это может быть совсем другой язык ... да ладно.

Karl 22.05.2015 21:41

Хотя это отличное предложение, это не прямой ответ на вопрос, оставьте это для комментариев. И поздравляю вас с тем, что вы знаете так много фреймворков, просто JQuery достаточно запутан, чтобы изучать больше фреймворков, потому что фреймворки имеют огромный недостаток, программист, который пишет фреймворк, думает не так, как вы, и, следовательно, очень трудно следовать их логике. В отличие от библиотек, которые просто предоставляют какой-то API, который позволяет делать четкие вещи, и, тем не менее, иногда, например, в библиотеках c, вы не знаете, нужно ли что-то free() или нет!

Iharob Al Asimi 04.09.2015 00:15

Я должен добавить к этому дополнительный комментарий, чтобы прояснить все «фреймворк» против «библиотеки». Фреймворк - это что-то построенное, чтобы действовать как слой вокруг или поверх чего-то другого. Библиотека - это собрание чего-то. На мой взгляд, jQuery (+ аналогичные) - это «фреймворки», которые полагаются на Javascript для создания «библиотеки» инструментов, ускоряющих выполнение задач. Вам не нужно самостоятельно учиться делать это, используя необработанный Javascript, или беспокоиться о совместимости браузера. Вы растете, чтобы учиться и полагаться на их методы и пользовательские функции Javascript. Отлично подходит для ускорения больших задач, но может раздуть более мелкие.

Adam Whateverson 23.08.2018 16:20

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

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; 

изменить: el = el.parentNode на: el = el.offsetParent; и, похоже, теперь он работает для вложенных фреймов ... Я думаю, это то, что вы хотели?

Adam 30.07.2009 00:19

Это решение неполное. Попробуйте поставить толстую рамку на div и несколько раз вложить ее. В любой версии Firefox (2–5) он будет отключен по ширине (а) границ (даже в режиме соответствия стандартам).

ck_ 05.08.2011 09:21

Вам также может понадобиться сделать _y+=Math.abs(document.body.offsetTop) и _x+=Math.abs(document.body.offsetLeft) для Firefox.

Azmisov 29.04.2012 09:15

нет ли более чистого способа сделать это, например, функций el.totalOffsetLeft и totalOffsetTop? В jQuery есть такая возможность, но жаль, что для этого нет официального метода, нужно ли нам ждать DOM4? Я создаю приложение холста HTML5, поэтому я думаю, что лучшим решением было бы вставить элемент холста в iframe, чтобы я мог получать реальные координаты с clientX и clientY, когда мы нажимаем на элемент.

baptx 30.05.2012 21:04

Итак, @Adam и meouw, вы говорите, что первый блок кода неправильный? Тогда почему бы не удалить это вообще? (Этот вопрос задавали довольно много зрителей на протяжении многих лет; было бы неплохо удалить вещи, если они ошибаются?)

Arjan 12.08.2012 03:35

(Кстати: блоки кода обсуждаются на Что делать, если кто-то добавляет альтернативный код с минимальными изменениями?, @Adam и meouw.)

Arjan 12.08.2012 03:42

@baptx: Я знаю, что это запоздалый ответ, но я не увидел ваш комментарий раньше. См. Мой ответ ниже для получения альтернативы, более соответствующей стандартам - вам даже не нужен резервный код, поскольку браузеры уже давно поддерживают его.

Andy E 08.02.2013 22:49

Эй, спасибо за ответ! Я все еще получаю неточные результаты. Вот мой код: stackoverflow.com/questions/15648464/…

Costa 27.03.2013 10:16

Для IE4 + (четыре) этого делать не нужно. См. Энди ответ.

Dan Dascalescu 21.07.2015 15:51

Смещение не работает точно в некоторых браузерах при масштабировании, можете посоветовать?

Nikos 13.08.2015 17:44

Также не будет работать для элементов svg (<svg>, <g>, path> и т. д.)

mrtnmgs 11.09.2019 18:09

Ошибки в мобильном Chrome для iOS, используйте вместо ответа Адама Гранта stackoverflow.com/a/28222246/1025702

Matt Fletcher 06.01.2020 14:14

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

например

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

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

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

Если страница включает - по крайней мере - любой «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];
};

как и в случае с другими решениями, даже с FF 24.4 приведенный выше код не работает, когда ширина границ существует как часть макета позиционирования.

rob 13.05.2014 00:46

Ты спасатель. Я работаю над некоторыми довольно серьезными ошибками GWT прямо сейчас, и добавление их в метод JSNI решает все мои проблемы !!

Will Byrne 11.06.2015 00:27

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

По какой-то причине он не дает таких же результатов в IE по сравнению с другими браузерами. Я думаю, что в IE он задает положение относительно окна, поэтому, если вы прокрутите, вы получите разные результаты в IE по сравнению с другими

Abdul Rahim Haddad 10.08.2013 20:19

offset () сбивает с толку масштабированием, по крайней мере, в Android Chrome, поэтому бесполезен. stackoverflow.com/a/11396681/1691517 показывает устойчивый к масштабированию способ.

Timo Kähkönen 31.05.2015 21:45

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

S P 07.03.2012 06:47

$ .browser больше не доступен в последней версии jQuery.

Gus 12.01.2014 22:22

к сожалению, даже с FF 24.4 приведенный выше код не работает, когда ширина границ существует как часть макета позиционирования.

rob 13.05.2014 00:43

Вы можете добавить два свойства к 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 обычно считается плохая идея. Это приводит к тому, что код очень сложно поддерживать. Кроме того, этот код не учитывает прокрутку.

Jared Forsyth 23.06.2015 00:58

Правильный подход - использовать element.getBoundingClientRect():

var rect = element.getBoundingClientRect();
console.info(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>');

А очень интересная статья о координатах JS. Эта статья нигде не упоминается о SO, она должна ..

e2-e4 19.02.2014 14:55

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

CpnCrunch 01.07.2014 06:30

@CpnCrunch: в каком браузере вы это видите? В моем тестировании код meouw и мой возвращают один и тот же результат независимо от поля элемента body.

Andy E 02.07.2014 12:43

Ломается как FF, так и хром. См. jsfiddle.net/D9VVy для ошибки (должны нарисовать два прямоугольника внутри друг друга). Рабочую версию (с использованием кода meouw) см. jsfiddle.net/Tn4FS

CpnCrunch 03.07.2014 21:49

На самом деле, я думаю, это зависит от того, что вы действительно хотите получить. Вопрос немного двусмысленный. Ваш ответ правильный, если вам просто нужны координаты относительно области просмотра или относительно элемента body, но это не поможет вам в случае, когда вам нужна абсолютная позиция элемента (что, как я полагаю, это то, чего хочет большинство людей) . Ответ meouw тоже не дает вам этого, если вы не удалите биты «-scrollLeft» и «-scrollTop».

CpnCrunch 03.07.2014 21:58

@CpnCrunch: теперь я понимаю, что вы имеете в виду; Я не понимал, что вы имеете в виду последнюю часть моего ответа. Когда у тела есть поле, его ограничивающая рамка будет смещена на это количество пикселей с каждой соответствующей стороны. В этом случае вам также придется вычесть вычисленный стиль полей из координат тела. Однако стоит отметить, что сброс CSS удаляет маржу из <body>.

Andy E 04.07.2014 19:14

Это решение elemRect.top - bodyRect.top и аналогично elemRect.left - bodyRect.left, к счастью, устойчиво к масштабированию. Смещение () jQuery дает разные результаты при масштабировании окна в Android Chrome. jQuery сдается в отношении offset(): размеры могут быть некорректными при увеличении страницы пользователем; браузеры не предоставляют API для обнаружения этого условия. Используя это решение для ответов, вам не нужен API для обнаружения условия масштабирования.

Timo Kähkönen 31.05.2015 20:12

@DanDascalescu см. Вторую часть моего ответа, где позиция элемента сравнивается с позицией основного элемента.

Andy E 21.07.2015 11:45

Как мне получить расстояние до самого верха страницы?

Finbar Maginn 07.12.2015 17:09
document.scrollingElement был бы здесь так полезен ...!
yckart 22.05.2016 14:41

@ RingØ +1 для pageXOffset и pageYOffset

ceving 10.12.2017 15:33

@ RingØ - отличная статья, но часть «Получение координат документа», в которой используется только pageXOffset, pageYOffset не универсальна, так как не учитывает вложенные прокручиваемые области.

sompylasar 08.02.2018 00:48

@ RingØ javascript.info - классный сайт, на нем много полезной информации.

Suraj Jain 12.04.2018 06:06
element.getBoundingClientRect().top не возвращает правильное верхнее смещение в случае элемента position: fixed в iOS (iPhone 8), если он содержит сфокусированный элемент ввода и виртуальная клавиатура сдвинулась вверх. Например, если фактическое смещение от верха окна составляет 200 пикселей, он будет сообщать, что это 420 пикселей, где 220 пикселей - это высота виртуальной клавиатуры. Если вы установите position: absolute элемента и разместите его в том же положении, как если бы он был зафиксирован, то вы получите правильные 200 пикселей. Я не знаю решения этой проблемы.
Jānis Elmeris 02.05.2018 20:58

Вау, это просто с другой планеты. Спасибо!

theVoogie 11.03.2019 16:31

Это классическое решение.

Wayne Wei 10.09.2019 10:29

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

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

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

Включение всех важных scrollTop / scrollLeft делает этот ответ немного более правильным.

scunliffe 07.12.2014 01:24

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

Я успешно использовал решение 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>

Ссылка в петле:

<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');");
        }
    });
}

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

Этот js-код мне помог, у меня есть старое приложение webforms, использующее несколько заполнителей, вставляющее страницы .aspx, и я не мог понять, как добавить к нему всплывающее окно, которое я создавал, чтобы поместить его в область просмотра, потому что все дерево DOM взломано с несколькими заполнителями и неправильной разметкой. Мне нужно было использовать body.getBoundingClientRect (), а затем использовать его верхнюю часть в позиционировании. Спасибо.

Brad Martin 15.08.2015 00:32

Самый чистый подход, который я нашел, - это упрощенная версия техники, используемой 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>

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

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

Для возврата в левую позицию необходимо вернуть:

    return offsetRect.left - rootRect.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

Только это решение работает для меня, когда элемент помещен в div, центрированный с использованием css top:50%, left:50%; transform:translate(-50%, -50%); ... отлично. Согласитесь с вопросом @ScottBiggs. Логично стремиться к простоте.

nelek 03.09.2015 23:57

возможно, это не победитель, потому что он такой же, как и решение Andy E, но не работает в старых браузерах <IE9

niltoid 11.06.2016 00:36

getBoundingClientRect вызывает резкий скачок перерисовки в моих диаграммах производительности

frumbert 22.11.2017 07:14

Разве это не должно быть ";" после возвращения {...}?

arrowman 30.01.2018 14:33

Как правило, не рекомендуется повторно использовать переменные, но здесь действительно странно повторно использовать el, почему бы не var rect = ... или что-то в этом роде? это намного понятнее.

tokland 25.06.2018 11:41

@tokland Я не думаю, что это «общее правило», хотя это особенность некоторых стилей программирования, таких как функциональное программирование. При этом я вижу, как это оптимизирует вышеизложенное. Вы можете передать суть? Рад рассмотреть возможность внесения изменений, направленных на дальнейшее улучшение. Спасибо.

Adam Grant 17.07.2018 19:25

@AdamGrant, я бы просто переименовал второй el, например в rect.

tokland 17.07.2018 22:21

Вы должны определить rect с помощью var, let или const. В противном случае он определяется как window.rect.

iota 08.08.2018 04:44

@ hev1 Также можно использовать this, но const имеет смысл. Просто изменилось. Спасибо!

Adam Grant 09.08.2018 21:13

@AdamGrant Нет проблем.

iota 10.08.2018 00:31
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2) вернет среднюю позицию элемента
abhishake 05.04.2019 13:35

Аккуратный! @abhishake

Adam Grant 11.04.2019 00:34

Почему я получаю, что el is null, с этим и любым другим ответом здесь. Использование на codepen или попытки тоже .. плюс getBoundingClientRect () должен иметь хотя бы 1 параметр нет?

Ryan Stone 17.11.2020 11:47

@RyanStone Не могли бы вы поделиться своей ручкой? Трудно поставить диагноз, ничего не видя.

Adam Grant 04.12.2020 20:41

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

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

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

Интересно ... но на Edge getAbsoluteOffsetFromBody (element) .top возвращает другое значение при прокрутке, в Chrome оно остается неизменным при прокрутке. Похоже, Edge корректирует положение прокрутки. Когда элемент прокручивается вне поля зрения, я получаю отрицательное значение.

Norman 13.01.2018 19:13

getAbsoluteOffsetFromRelative сделал мой день, мне пришлось воспроизвести всплывающую подсказку начальной загрузки без Javascript начальной загрузки, это мне очень помогло.

Nolyurn 13.08.2018 18:52

На всякий случай, если Meouw поменяет логин, ссылка для ответа: stackoverflow.com/a/442474/3654837. (Я не хочу натыкаться на эту старую ветку, так что да, я оставил комментарий)

Mukyuu 10.01.2020 10:22

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

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

К сожалению, это не работает для всех элементов, которые можно найти в современном HTML-документе. Например, встроенные элементы <svg> не имеют свойств offsetLeft, offsetTop и offsetParent.

Jonathan Eunice 19.10.2016 12:39

Это просто DIV или IMG, а не SVG. Посмотреть "Посмотрите пример координат"? вы можете найти объект svg - это вызов позиции getOffsetRect, попытаться и зависеть от работы объекта.

KingRider 19.10.2016 23:24

Как насчет того, чтобы передать идентификатор элемента, и он вернет 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');

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

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

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

window.visualViewport.pageTop

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

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


Обновлено:
Просто примечание относительно этого решения.
Хотя я все еще считаю то, что я обнаружил, очень ценным для ситуаций, в которых «... программно реагирует на движение прокручиваемых элементов». применимо. Лучшим решением возникшей у меня проблемы было использование CSS для установки позиция: липкая в элементе. Используя липкий, вы можете оставить элемент наверху без использования javascript (ПРИМЕЧАНИЕ: иногда это не будет работать так же эффективно, как изменение элемента на фиксированный, но для большинства применений липкий подход, вероятно, будет лучше)

ОБНОВЛЕНИЕ01:
Итак, я понял, что для другой страницы у меня было требование, когда мне нужно было определять положение элемента в умеренно сложной настройке прокрутки (параллакс плюс элементы, которые прокручиваются как часть сообщения). В этом сценарии я понял, что следующее дает значение, которое я использовал, чтобы определить, когда что-то делать:

  let bodyElement = document.getElementsByTagName('body')[0];
  let elementToTrack = bodyElement.querySelector('.trackme');
  trackedObjPos = elementToTrack.getBoundingClientRect().top;
  if (trackedObjPos > 264)
  {
    bodyElement.style.cssText = '';
  }

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

очень вероятно, что это будет первым из многих ответов, когда вы нажмете активный, чтобы отсортировать ответы

lucchi 01.06.2018 14:48

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

MER 01.06.2018 23:14

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

lucchi 02.06.2018 01:22

Get position of div in respect to left and 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 

Я проголосовал против, потому что нижний и правый угол не являются свойствами offset ()

MacroMan 08.05.2018 17:39

@MacroMan, я уважаю ваше решение, но я уже объяснял в тексте, что «нижний и правый код не тестируется.». Кроме того, я очень скоро обновлю свой код.

Vishal Kumar 08.05.2018 19:56

Я думаю, что это el.offsetTop и el.offsetLeft (OP ничего не говорит о jQuery ... Я не уверен, почему в вашем ответе также используется jQuery ...)

mesqueeb 10.07.2018 09:57

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

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

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

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

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

Это должно быть решением. Здесь нет длинного кода vs, он понятен и очень точен!

E Alexis MT 21.09.2019 04:07

что, если элемент находится внутри прокручиваемого элемента? Единственный способ сделать это - суммировать offsetTop всех родительских элементов, как предлагают другие ответы

Dmitri Pisarev 08.11.2019 14:11

Как утверждает Дмитрий, это неверно и очень некорректно. У него не должно быть столько голосов "за", как сейчас. Он ВСЕГДА также будет в прокручиваемом элементе, потому что сам документ можно прокручивать. Другими словами, если весь документ не умещается во вьюпорте, он всегда будет неверным, если пользователь вообще прокрутил главное окно.

Lev 19.01.2020 23:11

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

meo 01.11.2020 22:27

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

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

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

el.offsetTop + getParentOffsets(el);

Этот ответ выглядит так, как хотелось бы, за исключением того, что я получаю сообщение об ошибке «Uncaught ReferenceError: getParentOffset is not defined». Отсутствует буква "s", не так ли? Поэтому я изменил строку возврата функции, добавив букву «s» в «getParentOffset». Сейчас ошибок нет, но меня беспокоит, зная, что это была ошибка ...

kenneth558 18.02.2021 21:28
/**
 *
 * @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;
}

Спасибо Мышление за ответ, это всего лишь другая версия.

Это просто, как две строчки в JS:

var elem = document.getElementById("id");    
alert(elem.getBoundingClientRect());

Этот ответ неполный и ничего не добавляет к предыдущим ответам.

mfluehr 02.12.2020 18:18

Другие вопросы по теме