Книга: JavaScript. Подробное руководство, 6-е издание

15.8.5. Подробнее о размерах, позициях и переполнении элементов

15.8.5. Подробнее о размерах, позициях и переполнении элементов

Метод getBoundingClientRect() поддерживается всеми текущими броузерами, но если требуется обеспечить поддержку броузеров более старых версий, этот метод использовать нельзя и для определения размеров и позиций элементов следует применять более старые приемы. Размеры элементов определяются достаточно просто: доступные только для чтения свойства offsetWidth и offsetHeight любого HTML-элемента возвращают его размеры в пикселах. Возвращаемые размеры включают рамку элемента и отступы, но не включают поля, окружающие рамку снаружи.

Все HTML-элементы имеют свойства offsetLeft и offsetTop, возвращающие их координаты X и Y. Для многих элементов эти координаты откладываются относительно начала документа и непосредственно определяют позицию элемента. Но для потомков позиционируемых элементов и некоторых других элементов, таких как ячейки таблиц, эти свойства возвращают координаты относительно элемента-предка, а не документа. Свойство offsetParent определяет, относительно какого элемента исчисляются значения этих свойств. Если offsetРаrent имеет значение null, свойства содержат координаты относительно начала документа. Таким образом, в общем случае для определения позиции элемента е с помощью его свойств offsetLeft и offsetTop требуется выполнить цикл:

function getElementPosition(e) {
  var x = 0, у = 0;
  while(e != null) {
    x += e.offsetLeft;
    у += e.offsetTop;
    e = e.offsetParent;
  }
  return {x:x, у:у};
}

Выполняя обход цепочки, образуемой ссылками offsetParent, и накапливая смещения, эта функция вычисляет координаты указанного элемента относительно начала документа. (Напомню, что метод getBoundingClientRect(), напротив, возвращает координаты относительно начала видимой области.) Однако на этом тему позиционирования элементов нельзя считать исчерпанной - функция getElementPosition() не всегда вычисляет правильные значения, и ниже будет показано, как исправить эту ошибку.

В дополнение к множеству свойств offset все элементы документа определяют еще две группы свойств; имена свойств в первой группе начинаются с приставки client, а во второй группе - с приставки scroll. То есть каждый HTML-элемент имеет все свойства, перечисленные ниже:

offsetWidth
offsetHeight
offsetLeft
offsetTop
offsetParent
clientWidth
clientHeight
clientLeft
clientTop
scrollWidth
scrollHeight
scrollLeft
scrollTop

Чтобы понять разницу между группами свойств client и scroll, необходимо уяснить, что объем содержимого HTML-элемента может не умещаться в прямоугольную область, выделенную для этого содержимого, и поэтому отдельные элементы могут иметь собственные полосы прокрутки (смотрите описание CSS-атрибута overflow в разделе 16.2.6). Область отображения содержимого - это видимая область, подобная видимой области в окне броузера, и когда содержимое элемента не умещается в видимой области, необходимо принимать в учет позиции полос прокрутки элемента.

Свойства clientWidth и clientHeight похожи на свойства offsetWidth и offsetHeight, за исключением того, что они включают только область содержимого и отступы и не включают размер рамки. Кроме того, если броузер добавляет между рамкой и отступами полосы прокрутки, то свойства clientWidth и clientHeight не включают ширину полос прокрутки в возвращаемые значения. Обратите внимание, что для строчных элементов, таких как <i>, <code> и <span>, свойства clientWidth и clientHeight всегда возвращают 0.

Свойства clientWidth и clientHeight использовались в методе getViewportSize() из примера 15.9. В том случае, когда эти свойства применяются к корневому элементу документа (или телу элемента в режиме совместимости), они возвращают те же значения, что и свойства innerWidth и innerHeight окна.

Свойства clientLeft и clientTop не имеют большой практической ценности: они возвращают расстояние по горизонтали и вертикали между внешней границей отступов элемента и внешней границей его рамки. Обычно эти значения просто определяют ширину левой и верхней рамки. Однако если элемент имеет полосы прокрутки и если броузер помещает эти полосы прокрутки вдоль левого или верхнего края (что весьма необычно), значения свойств clientLeft и clientTop также будут включать ширину полос прокрутки. Для строчных элементов свойства clientLeft и clientTop всегда возвращают 0.

Свойства scrollWidth и scrollHeight определяют размер области содержимого элемента, плюс его отступы, плюс ширину и высоту области содержимого, выходящую за видимую область. Когда содержимое целиком умещается в видимой области, значения этих свойств совпадают со значениями свойств clientWidth и clientHeight. В противном случае они включают ширину и высоту области содержимого, выходящую за видимую область, и возвращают значения, превосходящие значения свойств clientWidth и clientHeight.

Наконец, свойства scrollLeft и scrollTop определяют позиции полос прокрутки элемента. Мы использовали эти свойства корневого элемента документа в методе getScrollOffsets() (пример 15.8), но они также присутствуют в любом другом элементе. Обратите внимание, что свойства scrollLeft и scrollTop доступны для записи и им можно присваивать значения, чтобы прокрутить содержимое элемента. (HTML-элементы не имеют метода scrollTo(), как объект Window.)

Когда документ содержит прокручиваемые элементы, содержимое которых не умещается в видимой области, объявленный выше метод getElementPosition() дает некорректные результаты из-за того, что он не учитывает позиции полос прокрутки. Ниже приводится исправленная версия, которая вычитает позиции полос прокрутки из накопленных смещений, т. е. преобразует координаты относительно начала документа в координаты относительно видимой области:

function getElementPos(elt) { var х = 0, у = 0;
  // Цикл, накапливающий смещения
  for(var е = elt; е != null; е = е.offsetParent) {
    х += e.offsetLeft;
    у += e.offsetTop;
  }
  // Еще раз обойти все элементы-предки, чтобы вычесть смещения прокрутки.
  // Он также вычтет позиции главных полос прокрутки и преобразует
  // значения в координаты видимой области.
  for(var e=elt.parentNode; е != null && e.nodeType == 1; e=e.parentNode) {
    x -= e.scrollLeft; у -= e.scrollTop;
  }
  return {x:x, y:y};
}

В современных броузерах этот метод getElementPos() возвращает те же координаты, что и метод getBoundingClientRect() (но он менее эффективен). Теоретически такая функция, как getElementPos(), могла бы использоваться в броузерах, не поддерживающих метод getBoundingClientRect(). Однако броузеры, не поддерживающие getBoundingClientRect(), имеют массу несовместимостей в механизме позиционирования элементов, и поэтому в них такая простая функция оказывается ненадежной. Клиентские библиотеки, такие как jQuery, включают функции вычисления позиций элементов, которые дополняют этот простой алгоритм множеством проверок, учитывающих несовместимости между броузерами. Если вам потребуется определять позиции элементов в броузерах, не поддерживающих getBoundingClientRect(), то для этих целей лучше использовать библиотеку, например, jQuery.

Оглавление книги


Генерация: 1.165. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз