Метрики HTML-документа

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

<!DOCTYPE html>
<html>
<head>
    <title>Уроки по JavaScript</title>
<style>
body {
    margin: 0;
}
.message {
    border: 20px solid #007700;
    width: 300px;
    height: 200px;
    overflow: auto;
    padding: 10px;
    background: #eee;
    font-size: 24px;
    margin: 50px 0 0 100px;
}
</style>
</head>
<body>
<div class="message">
<h3>Уроки по JavaScript</h3>
<p>На этом занятии мы рассмотрим метрики, используемые для 
позиционирования элементов и их содержимого 
на экране браузера. Чтобы лучше их понять, рассмотрим такой рисунок.</p>
</div>
<script>
</script>
</body>
</html>

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

<!DOCTYPE html>

который говорит браузеру, что HTML-страницу следует воспринимать по стандарту HTML 5.x. От этого могут зависеть значения метрик, о которых здесь пойдет речь.

Теперь смотрите, у нашего блока div реальные размеры составляют 360 на 260 пикселей и имеется множество различных отступов: margin, border и padding. Так вот, ко всем этим параметрам блока div можно получить доступ из JavaScript. Они и называются метриками. Рассмотрим их по порядку. Начнем со свойств:

  • elem.clientWidth – содержит ширину клиентской области (в пикселах);
  • elem.clientHeight – содержит высоту клиентской области (в пикселах).

Выведем их в консоль:

let elem = document.querySelector("div.message");
console.log(elem.clientWidth, elem.clientHeight);

Увидим значения: 305 и 220 пикселей. Откуда взялись такие числа? Изначально мы задавали ширину, равную 300 пикселей. К этому значению прибавляются отступы padding по 10 пикселей и вычитается ширина полосы прокрутки, которая в данном случае съедает 15 пикселей, получаем:

clientWidth = 300+10+10-15 = 305

Аналогично вычисляется размер клиентской области по вертикали: в ней учитывается базовая высота блока div в 200 пикселей и по 10 пикселей отступы padding, имеем:

clientHeight = 200+10+10 = 220

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

elem.clientHeight = 100;

не получится. Если нам нужно изменить высоту элемента, то следует использовать соответствующие свойства из style:

elem.style.height = 100+"px";

с обязательным указанием единиц измерения (в данном случае – пиксели). Аналогично через свойство width меняется ширина блока.

Следующие метрики:

  • elem.scrollTop – высота прокрутки содержимого блока;
  • elem.scrollLeft – величина прокрутки содержимого в левую сторону блока;
  • elem.scrollWidth – ширина содержимого с учетом прокрутки;
  • elem.scrollHeight – высота содержимого с учетом прокрутки.

Все эти свойства для наглядности изображены на этом рисунке.

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

<div style="width: 500px">

и будем отображать величины каждую секунду:

let elem = document.querySelector("div.message");
setInterval(function() {
      console.log(elem.scrollTop, elem.scrollLeft, elem.scrollWidth, elem.scrollHeight);
}, 1000);

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

Величины scrollLeft и scrollTop можно менять и осуществлять программный скроллинг содержимого. Например, если мы пропишем вот такой код:

elem.scrollTop = 100;

то при обновлении документа увидим смещение содержимого по вертикали. Аналогично и для

elem.scrollLeft += 20;

мы его здесь ему присвоили значение через оператор +=, то есть, к предыдущему значению добавили еще 20 пикселей. Так тоже можно делать.

А вот свойства scrollWidth и scrollHeight менять уже нельзя, они доступны только для чтения.

Следующие свойства:

  • elem.offsetLeft – содержит смещение блока от левого края;
  • elem.offsetTop – содержит смещение блока от верхнего края.

Данные свойства обычно отсчитывают смещения относительно окна браузера (элемента body), но в общем случае относительно своего предка, указанного в свойстве offsetParent:

console.log(elem.offsetParent);

В данном случае увидим элемент body. Визуально их можно представить так:

Выведем их в консоль

console.log(elem.offsetLeft, elem.offsetTop);

и убедимся, что они принимают заданные в CSS-стилях значения. На этом же рисунке отмечены еще два свойства:

  • elem.clientLeft – смещение слева внутренней части области от края элемента (в данном случае блока div);
  • elem.clientTop – смещение сверху внутренней части области от края элемента (в данном случае блока div).

В нашем примере эти свойства будут равны 20 пикселам – толщине рамки, указанной в CSS-свойстве border. Выведем их в консоль:

console.log(elem.clientLeft, elem.clientTop);

и видим значения 20.

Наконец, последние две метрики:

  • elem.offsetWidth – ширина элемента с учетом всех отступов;
  • elem.offsetHeight – высота элемента с учетом всех отступов.

То есть, в нашем случае – это будут полные размеры блока div. Выведем их в консоль:

console.log(elem.offsetWidth, elem.offsetHeight);

и видим значения 360 на 260 пикселей.

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

let styles = getComputedStyle(elem, [pseudo]);

о которой мы говорили на предыдущем занятии? В действительности нет, так как реальные значения элементов в окне браузера могут отличаться от значений свойств, указанных в CSS. Кроме того, в CSS свойства могут быть вообще не указаны, например, высота элемента – она часто определяется реальным содержимым. Или же, ширина заданная как auto:

width: auto;

не может быть переведена в пиксели функцией getComputedStyle: мы там так auto и увидим. Поэтому, если вам нужны актуальные значения метрик элемента, то следует использовать свойства, рассмотренные на этом занятии.

Видео по теме