- Координаты относительно окна и документа
- Получение координат элемента
- Получение элемента по координатам:
elementFromPoint(x,y) - Координаты на экране
screenX/screenY - Итого
В браузере есть три координатные системы.
- Относительно документа
pageX/pageY - Точка начала координат лежит в левом верхнем углу страницы.
- Относительно окна
clientX/clientY - Начало координат лежит в левом верхнем углу текущей видимой области.
- Относительно экрана
screenX/screenY - Начало координат — левый-верхний угол экрана.
Координатами элемента, для краткости, называются координаты его левого верхнего угла.
Координаты относительно окна и документа
Когда страница не прокручена, точки начала координат относительно окна (clientX,clientY) и документа (pageX,pageY) совпадают:

Например, координаты элемента с надписью «STANDARDS» равны расстоянию от верхней/нижней границы окна:

Прокрутим страницу, чтобы элемент был на самом верху:
Посмотрите на рисунок ниже.
- Координата
clientYизменилась. Она теперь равна0, т.к. элемент на самом верху окна. - Координата
pageYотсчитывается от левого-верхнего угла документа, поэтому осталась такой же. Она не зависит от прокрутки.

Итак, координаты pageX,pageY не меняются при прокрутке, в отличие от clientX,clientY. Можно сказать и по-другому. Разность pageY-clientY — это в точности размер текущей прокрученной области.
Получение координат элемента
Координаты в окне: elem.getBoundingClientRect()
Этот метод описан в стандарте W3C и поддерживается всеми современными браузерами(и даже IE6+).
Он возвращает размеры прямоугольника, который охватывает элемент, в виде объекта со свойствами: top, left, right, bottom.
Эти 4 числа — координаты верхнего левого и нижнего правого углов элемента относительно окна. Например, кликните на кнопку, чтобы увидеть координаты ее углов:
<input id="brTest" type="button" value="Show button.getBoundingClientRect()" onclick='showRect(this)'/>
<script>
function showRect(elem) {
var r = elem.getBoundingClientRect()
alert("Top/Left: "+r.top+" / "+r.left)
alert("Right/Bottom: "+r.right+" / "+r.bottom)
}
</script>
Координаты elem.getBoundingClientRect() — относительно окна, а не документа.
Например, если вы прокрутите эту страницу так, что кнопка будет становить ближе к верху окна, то ее top-координата будет стремиться к 0, потому что он считается относительно окна.
Чтобы посчитать ее относительно документа, нужно добавить к ней величину прокрутки.
elem.getBoundingClientRect()?Браузер отображает любое содержимое, используя прямоугольники.
В случае с блочным элементом, таким как DIV - элемент сам по себе образует прямоугольник.
Но если элемент строчный и содержит в себе длинный текст, то каждая строка будет отдельным прямоугольником, с одинаковой высотой но разной длиной (у каждой строки — своя длина).
Более подробно это описано в: спецификации.
Если обобщить, содержимое элемента может отображаться в одном прямоугольнике или в нескольких.
Эти прямоугольники можно получить с помощью elem.getClientRects(). А метод elem.getBoundingClientRect() возвращает один охватывающий прямоугольник для всех из getClientRects().
Координаты в документе
Готовой функции для координат элемента в документе нет. Но её можно написать самим.
Наша фукнция getCoords(elem) будет брать результат elem.getBoundingClientRect() и прибавлять текущую прокрутку документа.
Результат: объект с координатами {left: .., top: ..}
function getCoords(elem) {
// (1)
var box = elem.getBoundingClientRect();
var body = document.body;
var docEl = document.documentElement;
// (2)
var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
// (3)
var clientTop = docEl.clientTop || body.clientTop || 0;
var clientLeft = docEl.clientLeft || body.clientLeft || 0;
// (4)
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
// (5)
return { top: Math.round(top), left: Math.round(left) };
}
Разберем что и зачем, по шагам:
- Получаем прямоугольник.
- Считаем прокрутку страницы. Все браузеры, кроме IE<9 поддерживают свойство
pageXOffset/pageYOffset. В более старых IE, когда установлен DOCTYPE, прокрутку можно получить изdocumentElement, ну и наконец если DOCTYPE некорректен — использоватьbody. - В IE документ может быть смещен относительно левого верхнего угла. Получим это смещение.
- Добавим прокрутку к координатам окна и вычтем смещение
html/body, чтобы получить координаты всего документа. - Координаты округляются вызовом
Math.round()т.к. в Firefox бывают дробные пиксели.
Устаревший метод: offset*
Есть альтернативный способ нахождения координат — это пройти всю цепочку offsetParent от элемента вверх и сложить отступы offsetLeft/offsetTop.
Мы разбираем его здесь с учебной целью, т.к. он используется лишь в старых браузерах.
Вот функция, реализующая такой подход.
function getOffsetSum(elem) {
var top = 0, left = 0;
while(elem) {
top = top + parseInt(elem.offsetTop);
left = left + parseInt(elem.offsetLeft);
elem = elem.offsetParent;
}
return {top: top, left: left};
}
Она работает, но у этого подхода есть как минимум два недостатка.
- Он ненадежный. Разные браузеры преподносят «сюрпризы», включая или выключая размер рамок и прокруток из
offsetTop/Left. - Он медленный, ведь нам каждый раз приходиться проходить всю цепочку
offsetParent.
Конечно, можно написать кроссбраузерный код, который будет учитывать все нюансы, но давайте-ка лучше посмотрим альтернативное решение, которые работает во всех современных браузерах, включая Firefox 3+ и Opera 9.62+, Safari/Chrome и IE6+.
Сравнение offset* с getBoundingClientRect
Сравним методы для вычисления координат, описанные выше.
В следующем примере есть 3 вложенных DIV. Все они имеют border, кое-кто из них имеет position/margin/padding.
Кликните по внутреннему элементу, чтобы увидеть результаты обоих методов: getOffsetSum и getCoords, а так же реальные координаты курсора - event.pageX/pageY (мы обсудим их позже в статье Устранение IE-несовместимостей: «fixEvent»).
Все значения выводятся под DIV-ами.
getOffsetSum и getCoordsКликните в любом месте желтого блока и вы увидите результаты для getOffsetSum(elem) и getCoords(elem). Обратите внимание, что они обычно не совпадают.
Для того, чтобы узнать, какой же результат верный, кликните в левом верхнем углу желтого блока. Он расположен в левом верхнем углу черной границы.
Будут видны абсолютные координаты мыши, так что вы можете сравнить их с getOffsetSum/getCoords.
Попробуйте, чтобы увидеть, что getCoords всегда возвращает верное значение
.
Комбинированный подход
Фреймворки, которые хотят быть совместимыми со старыми браузерами, используют комбинированный подход:
function getOffset(elem) {
if (elem.getBoundingClientRect) {
return getCoords(elem);
} else { // старый браузер
return getOffsetSum(elem);
}
}
function getOffsetSum(elem) {
var top=0, left=0
while(elem) {
top = top + parseInt(elem.offsetTop)
left = left + parseInt(elem.offsetLeft)
elem = elem.offsetParent
}
return {top: top, left: left}
}
function getCoords(elem) {
var box = elem.getBoundingClientRect()
var body = document.body;
var docEl = document.documentElement;
var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
var clientTop = docEl.clientTop || body.clientTop || 0;
var clientLeft = docEl.clientLeft || body.clientLeft || 0;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return { top: Math.round(top), left: Math.round(left) };
}
function getOffset(elem) {
if (elem.getBoundingClientRect) {
return getCoords(elem)
} else {
return getOffsetSum(elem)
}
}
Получение элемента по координатам: elementFromPoint(x,y)
Обратная задача — «получить элемент по координатам в документе» появится при работе с событиями мыши.
Для её решения есть метод document.elementFromPoint(clientX, clientY).
Параметры clientX/clientY — координаты относительно окна.
Например: введите координаты в форме ниже. Соответствующий элемент на этой странице будет подсвечен стилем background-color:red. При повторном нажатии подсветка снимается.
Код функции подсветки:
/* x,y - координаты относительно окна */
function highlightRedXY(x,y) {
*!*
var el = document.elementFromPoint(x, y);
*/!*
el.style.backgroundColor = (el.style.backgroundColor == 'red') ? '' : 'red';
}
Обратите внимание — при прокрутке страницы на тех же координатах будут новые элементы. Это как раз потому, что координаты в этой функции — относительно окна, а не документа.
Координаты на экране screenX/screenY
Координаты относительно экрана screenX/screenY отсчитываются от его левого-верхнего угла. Имеется в виду именно весь экран, а не окно браузера.

Таки координаты редко используются. Но они могут быть полезны, например, при работе с мобильными устройствами.
Общая информация об экране хранится в глобальной переменной screen:
// общая ширина/высота alert( screen.width + ' x ' + screen.height ); // доступная ширина/высота (за вычетом таскбара и т.п.) alert( screen.availWidth + ' x ' + screen.availHeight); // есть и ряд других свойств screen (см. документацию)
Координаты левого-верхнего угла браузера на экране хранятся в window.screenX, window.screenY (не поддерживаются IE<9):
alert("Браузера находится на " + window.screenX + "," + window.screenY);
Они могут быть и меньше нуля, если окно частично вне экрана.
Координаты DOM-элемента относительно экрана получить нельзя. Браузер не предоставляет свойств и методов для этого.
Итого
У любой точки в браузере есть координаты:
- Относительно окна
window. - Относительно документа
document— не меняются при прокрутке. - Относительно экрана
screen.
Начало координат — в левом-верхнем углу окна/документа/экрана.
Координаты элемента относительно окна: elem.getBoundingClientRect(), для получения относительно документа — добавляем прокрутку.
В старых Firefox, Chrome/Safari и Opera нескольких лет давности метода getBoundingClientRect нет, для них — можно использовать суммирование offsetTop/Left.
Координаты будут нужны нам далее, при работе с событиями мыши (координаты клика) и элементами (перемещение).
Комментарии
- Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
- Если ваш комментарий касается задачи -- откройте её в отдельном окне и напишите там.
- Комментарии без смысла, с рекламой или не о статье вообще - удаляются.