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

Тестовый блок

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

Вот этот блок:

<div id="elem">Текст</div>
#elem {
	width: 200px;
	height: 200px;
	padding: 30px;
	border: 20px solid #BCBCBC;
	overflow: auto;
}

Результат выполнения кода, если текста мало:

Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis.

Результат выполнения кода, если текста много:

Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis. Maecenas magna velit, hendrerit non commodo id, sagittis ut nisi. Etiam ex sapien, iaculis nec eros non, venenatis porttitor eros. Phasellus imperdiet interdum congue. Nam tempor justo id vestibulum imperdiet. Donec mauris ipsum, accumsan non ultrices vitae, egestas nec lorem. Suspendisse convallis, diam sed fermentum rutrum, mauris libero tristique ante, vitae pharetra eros urna non velit. Phasellus tortor purus, vehicula et ex in, sagittis rhoncus sapien.

Все примеры ниже мы будем изучать по этому блоку или его модификациям.

Расширение элементов

Давайте рассмотрим блок, у которого задана ширина 200px, padding 30px и граница 20px. Тут CSS имеет определенный нюанс в работе: фактическая ширина блока будет не 200px, как это задано через width: 200px, а 300! Почему так: потому что padding и граница расширяют блок. Получается, реальный размер блока такой: ширина из width (200px) + левый padding (30px) + правый padding (30px) + левая граница (20px) + правая граница (20px) - итого 300px.

Давайте убедимся в этом на следующем примере - зададим блоку padding и границу - и вы увидите как он расширится (для сравнения рядом приведен блок без границы и padding - вот его-то ширина будет реально 200px):

#elem1 {
	width: 200px;
	height: 200px;
	padding: 30px;
	border: 20px solid #BCBCBC;
}

#elem2 {
	width: 200px;
	height: 200px;
	background: #BCBCBC;
}

Блок будет шириной не 200px, а 300:

Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis.
Ширина 200px

Выше речь шла о ширине, но то же самое касается и высоты блока - и padding и граница расширяют блок и по высоте тоже.

Подводные камни при работе с CSS

Давайте в теперь поговорим о проблемах, которые возникают, если вы хотите прочитать значения CSS свойств через JavaScript вот таким образом: элемент.style.свойство.

Проблема в том, что так можно прочитать только те свойства, которые были заданы через атрибут style, а те свойства, которые были заданы через CSS - прочитать нельзя.

Давайте посмотрим на примерах. Прочитаем ширину элемента, заданную через атрибут style:

<div id="elem" style="width: 200px;">Текст</div>
var elem = document.getElementById('elem');
alert(elem.style.width); //выведет '200px'

А сейчас сначала назначим ширину через JavaScript, а потом прочитаем ее - так тоже будет работать, так как здесь по сути JavaScript модифицирует атрибут style:

<div id="elem">Текст</div>
var elem = document.getElementById('elem');
elem.style.width = '200px'; //запишем новую ширину
alert(elem.style.width); //выведет '200px'

А вот если мы захотим прочитать ширину, установленную через CSS (или в отдельном файле или через тег style), то у нас ничего не получится:

#elem {
	width: 200px;
	height: 200px;
	padding: 30px;
	border: 20px solid #BCBCBC;
	overflow: auto;
}
var elem = document.getElementById('elem');
alert(elem.style.width); //алерт будет пустой

Нажмите на кнопку - и вы увидите результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis.

Однако, способ добраться до недоступных CSS свойств все-таки есть - следует использовать функцию getComputedStyle, которую мы сейчас и разберем.

Функция getComputedStyle

Функция getComputedStyle позволяет получить значение любого CSS свойства элемента, даже из CSS файла.

Как она работает (внимание: не так как мы ожидаем): параметром функция принимает элемент, а возвращает объект, который содержит в себе все CSS свойства переданного элемента.

Давайте положим этот объект в переменную style. Название произвольное, это просто переменная - как придумаем, так и будем обращаться:

var elem = document.getElementById('elem');
var style = getComputedStyle(elem); //в style лежат CSS свойства

Давайте выведем, к примеру, ширину. Это делается так - style.width:

var elem = document.getElementById('elem');
var style = getComputedStyle(elem);
alert(style.width);

Чтобы вывести, к примеру, левый padding - делаем так - style.paddingLeft:

var elem = document.getElementById('elem');
var style = getComputedStyle(elem);
alert(style.paddingLeft);

В следующем примере мы выведем все интересующие нас CSS свойства для нашего элемента:

var elem = document.getElementById('elem');

var style = getComputedStyle(elem);
alert('paddingLeft: ' + style.paddingLeft); //выведет '30px'
alert('borderTopWidth: ' + style.borderTopWidth); //выведет '20px'
alert('borderTopStyle: ' + style.borderTopStyle); //выведет 'solid'

Нажмите на кнопку - и вы увидите результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis.

Неточность getComputedStyle

Иногда функция getComputedStyle работает не совсем корректно с шириной и высотой. Это связано с тем, что padding и граница расширяют блок. В следующем примере блоку задана ширина 200px, а также граница и padding. Реальная ширина блока 300px, но getComputedStyle все равно выведет 200px:

#elem {
	width: 200px;
	height: 200px;
	padding: 30px;
	border: 20px solid #BCBCBC;
	overflow: auto;
}
var elem = document.getElementById('elem');

var style = getComputedStyle(elem);
alert('width: ' + style.width); //выведет '200px'

Нажмите на кнопку - и вы увидите результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis.

То есть: получается, что getComputedStyle игнорирует расширение блока и показывает его размеры так, как будто этого расширения не было.

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

Вычисленные значения

Есть еще один нюанс: если ширина задана в % - то после работы getComputedStyle мы увидим ее в px. То есть по сути мы получаем не заданную ширину, а вычисленную. Смотрите на следующем примере:

#elem {
	width: 30%; /* ширина задана в % */
	height: 200px;
	padding: 30px;
	border: 20px solid #BCBCBC;
	overflow: auto;
}
var elem = document.getElementById('elem');

var style = getComputedStyle(elem);
alert('width: ' + style.width);

Нажмите на кнопку - и вы увидите ширину в пикселях, а не в %:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis.

Переходим к метрикам

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

Свойства clientLeft и clientTop

Свойство clientLeft содержит в себе ширину левой границы, а свойство clientTop - ширину верхней.

Посмотрим на следующем примере:

var elem = document.getElementById('elem');
alert('clientTop: ' + elem.clientTop); //выведет 20
alert('clientLeft: ' + elem.clientLeft); //выведет 20

Нажмите на кнопку - и вы увидите результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis.

Свойства offsetWidth и offsetHeight

Свойства offsetWidth и offsetHeight содержат в себе полную ширину и высоту элемента с учетом расширения padding и границей. Давайте выведем эти метрики для нашего тестового элемента:

var elem = document.getElementById('elem');
alert('offsetWidth: ' + elem.offsetWidth); //выведет 300
alert('offsetHeight: ' + elem.offsetHeight); //выведет 300

Нажмите на кнопку - и вы увидите результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis. Maecenas magna velit, hendrerit non commodo id, sagittis ut nisi. Etiam ex sapien, iaculis nec eros non, venenatis porttitor eros. Phasellus imperdiet interdum congue. Nam tempor justo id vestibulum imperdiet. Donec mauris ipsum, accumsan non ultrices vitae, egestas nec lorem. Suspendisse convallis, diam sed fermentum rutrum, mauris libero tristique ante, vitae pharetra eros urna non velit. Phasellus tortor purus, vehicula et ex in, sagittis rhoncus sapien.

Свойства clientWidth и clientHeight

Свойство clientWidth содержит ширину текста + padding. То есть это полная ширина элемента за вычетом границы и полосы прокрутки. Свойство clientHeight - то же самое для высоты.

Давайте выведем clientWidth для нашего тестового элемента. Результат зависит от наличия полосы прокрутки. Если ее нет - увидим 260, а если есть - 260 минус полоса прокрутки:

var elem = document.getElementById('elem');
alert('clientWidth: ' + elem.clientWidth);

Без полосы. Нажмите на кнопку - и вы увидите результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis.

С полосой. Нажмите на кнопку - и вы увидите результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis. Maecenas magna velit, hendrerit non commodo id, sagittis ut nisi. Etiam ex sapien, iaculis nec eros non, venenatis porttitor eros. Phasellus imperdiet interdum congue. Nam tempor justo id vestibulum imperdiet. Donec mauris ipsum, accumsan non ultrices vitae, egestas nec lorem. Suspendisse convallis, diam sed fermentum rutrum, mauris libero tristique ante, vitae pharetra eros urna non velit. Phasellus tortor purus, vehicula et ex in, sagittis rhoncus sapien.

Свойства scrollLeft и scrollTop

Свойства scrollLeft и scrollTop содержат в себе информацию о том, на сколько элемент, имеющий полосу прокрутки, прокручен слева и сверху.

В следующем примере по клику на кнопку значение scrollTop (прокрутка сверху):

var elem = document.getElementById('elem');
alert('scrollTop: ' + elem.scrollTop);

Прокрутите элемент и нажмите на кнопку - вы увидите, на сколько он прокручен:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis. Maecenas magna velit, hendrerit non commodo id, sagittis ut nisi. Etiam ex sapien, iaculis nec eros non, venenatis porttitor eros. Phasellus imperdiet interdum congue. Nam tempor justo id vestibulum imperdiet. Donec mauris ipsum, accumsan non ultrices vitae, egestas nec lorem. Suspendisse convallis, diam sed fermentum rutrum, mauris libero tristique ante, vitae pharetra eros urna non velit. Phasellus tortor purus, vehicula et ex in, sagittis rhoncus sapien.

Свойства scrollLeft и scrollTop можно не только прочитывать. Можно также присвоить им нужное значение - и элемент прокрутися в нужное положение. Давайте убедимся в этом на следующем примере:

var elem = document.getElementById('elem');
elem.scrollTop = 100;

Нажмите на кнопку - элемент прокрутится в положение '100px сверху':



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis. Maecenas magna velit, hendrerit non commodo id, sagittis ut nisi. Etiam ex sapien, iaculis nec eros non, venenatis porttitor eros. Phasellus imperdiet interdum congue. Nam tempor justo id vestibulum imperdiet. Donec mauris ipsum, accumsan non ultrices vitae, egestas nec lorem. Suspendisse convallis, diam sed fermentum rutrum, mauris libero tristique ante, vitae pharetra eros urna non velit. Phasellus tortor purus, vehicula et ex in, sagittis rhoncus sapien.

А в следующем примере мы будем прокручивать элемент на 100px от текущего положения:

var elem = document.getElementById('elem');
elem.scrollTop = elem.scrollTop + 100;

Нажмите на кнопку, чтобы увидеть результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis. Maecenas magna velit, hendrerit non commodo id, sagittis ut nisi. Etiam ex sapien, iaculis nec eros non, venenatis porttitor eros. Phasellus imperdiet interdum congue. Nam tempor justo id vestibulum imperdiet. Donec mauris ipsum, accumsan non ultrices vitae, egestas nec lorem. Suspendisse convallis, diam sed fermentum rutrum, mauris libero tristique ante, vitae pharetra eros urna non velit. Phasellus tortor purus, vehicula et ex in, sagittis rhoncus sapien.

Свойства scrollWidth и scrollHeight

Следующее два свойства scrollWidth и scrollHeight содержат в себе полную ширину и высоту элемента с учетом прокрученной части.

Давайте изучим их работу на следующем примере: выведем полную высоту нашего тестового элемента:

var elem = document.getElementById('elem');
alert('scrollHeight: ' + elem.scrollHeight);

Нажмите на кнопку - и вы увидите результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis. Maecenas magna velit, hendrerit non commodo id, sagittis ut nisi. Etiam ex sapien, iaculis nec eros non, venenatis porttitor eros. Phasellus imperdiet interdum congue. Nam tempor justo id vestibulum imperdiet. Donec mauris ipsum, accumsan non ultrices vitae, egestas nec lorem. Suspendisse convallis, diam sed fermentum rutrum, mauris libero tristique ante, vitae pharetra eros urna non velit. Phasellus tortor purus, vehicula et ex in, sagittis rhoncus sapien.

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

Пусть elem - это наш элемент. Тогда, чтобы распахнуть элемент на полную высоту нужно в elem.style.height записать значение elem.scrollHeight. Учтите, что в style.height значения следует записывать в пикселях, а scrollHeight возвращает значение без пикселей. То есть нужно сделать так:

elem.style.height = elem.scrollHeight + 'px'; //прибавим 'px'

Кроме того, для корректной работы из elem.scrollHeight следует вычесть верхний и нижний padding.

Итак, с учетом всего перечисленного распахнем элемент на полную высоту:

var elem = document.getElementById('elem');

var style = getComputedStyle(elem);
var paddingTop = parseInt(style.paddingTop);
var paddingBottom = parseInt(style.paddingBottom);

elem.style.height = (elem.scrollHeight - paddingTop - paddingBottom) + 'px';

Нажмите на кнопку - и вы увидите результат:



Lorem ipsum dolorsit amet consectetur adipiscing elit. Sed viverra mollis lorem, fringilla dapibus nisi commodo interdum. Vivamus in turpis quis purus dapibus aliquam id nec velit. In at aliquet sem, a rutrum neque. Vestibulum posuere lobortis accumsan. Etiam non tincidunt erat, vel condimentum turpis. Maecenas magna velit, hendrerit non commodo id, sagittis ut nisi. Etiam ex sapien, iaculis nec eros non, venenatis porttitor eros. Phasellus imperdiet interdum congue. Nam tempor justo id vestibulum imperdiet. Donec mauris ipsum, accumsan non ultrices vitae, egestas nec lorem. Suspendisse convallis, diam sed fermentum rutrum, mauris libero tristique ante, vitae pharetra eros urna non velit. Phasellus tortor purus, vehicula et ex in, sagittis rhoncus sapien.

Свойство offsetParent

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

Свойства offsetLeft и offsetTop

Свойства offsetLeft и offsetTop содержат в себе позицию в пикселях левого верхнего угла блока относительно его offsetParent.