Сейчас мы с вами будем разбираться с метриками элементов. Метрики - это специальные свойства, с помощью которых можно получить размеры элемента с учетом границы, padding и полосы прокрутки.
Тестовый блок
Перед тем, как приступить к обсуждению метрик, рассмотрим тестовый блок. У этого блока ограничена ширина и высота, добавлены padding, граница, а также overflow: auto, чтобы, если текста достаточно много, - появилась полоса прокрутки.
Вот этот блок:
<div id="elem">Текст</div>
#elem {
width: 200px;
height: 200px;
padding: 30px;
border: 20px solid #BCBCBC;
overflow: auto;
}
Результат выполнения кода, если текста мало:
Результат выполнения кода, если текста много:
Все примеры ниже мы будем изучать по этому блоку или его модификациям.
Расширение элементов
Давайте рассмотрим блок, у которого задана ширина 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:
Выше речь шла о ширине, но то же самое касается и высоты блока - и 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); //алерт будет пустой
Нажмите на кнопку - и вы увидите результат:
Однако, способ добраться до недоступных 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'
Нажмите на кнопку - и вы увидите результат:
Неточность 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'
Нажмите на кнопку - и вы увидите результат:
То есть: получается, что 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);
Нажмите на кнопку - и вы увидите ширину в пикселях, а не в %:
Переходим к метрикам
Давайте теперь перейдем к метрикам. Напоминаю, что метрики - это свойства, которые содержат характеристики элемента: его полную ширину (с учетом расширения, которое мы разбирали ранее), ширину без границы, ширину без padding, с учетом полосы прокрутки и без. И так далее. Давайте разбираться.
Свойства clientLeft и clientTop
Свойство clientLeft содержит в себе ширину левой границы, а свойство clientTop - ширину верхней.
Посмотрим на следующем примере:
var elem = document.getElementById('elem');
alert('clientTop: ' + elem.clientTop); //выведет 20
alert('clientLeft: ' + elem.clientLeft); //выведет 20
Нажмите на кнопку - и вы увидите результат:
Свойства offsetWidth и offsetHeight
Свойства offsetWidth и offsetHeight содержат в себе полную ширину и высоту элемента с учетом расширения padding и границей. Давайте выведем эти метрики для нашего тестового элемента:
var elem = document.getElementById('elem');
alert('offsetWidth: ' + elem.offsetWidth); //выведет 300
alert('offsetHeight: ' + elem.offsetHeight); //выведет 300
Нажмите на кнопку - и вы увидите результат:
Свойства clientWidth и clientHeight
Свойство clientWidth содержит ширину текста + padding. То есть это полная ширина элемента за вычетом границы и полосы прокрутки. Свойство clientHeight - то же самое для высоты.
Давайте выведем clientWidth для нашего тестового элемента. Результат зависит от наличия полосы прокрутки. Если ее нет - увидим 260, а если есть - 260 минус полоса прокрутки:
var elem = document.getElementById('elem');
alert('clientWidth: ' + elem.clientWidth);
Без полосы. Нажмите на кнопку - и вы увидите результат:
С полосой. Нажмите на кнопку - и вы увидите результат:
Свойства scrollLeft и scrollTop
Свойства scrollLeft и scrollTop содержат в себе информацию о том, на сколько элемент, имеющий полосу прокрутки, прокручен слева и сверху.
В следующем примере по клику на кнопку значение scrollTop (прокрутка сверху):
var elem = document.getElementById('elem');
alert('scrollTop: ' + elem.scrollTop);
Прокрутите элемент и нажмите на кнопку - вы увидите, на сколько он прокручен:
Свойства scrollLeft и scrollTop можно не только прочитывать. Можно также присвоить им нужное значение - и элемент прокрутися в нужное положение. Давайте убедимся в этом на следующем примере:
var elem = document.getElementById('elem');
elem.scrollTop = 100;
Нажмите на кнопку - элемент прокрутится в положение '100px сверху':
А в следующем примере мы будем прокручивать элемент на 100px от текущего положения:
var elem = document.getElementById('elem');
elem.scrollTop = elem.scrollTop + 100;
Нажмите на кнопку, чтобы увидеть результат:
Свойства scrollWidth и scrollHeight
Следующее два свойства scrollWidth и scrollHeight содержат в себе полную ширину и высоту элемента с учетом прокрученной части.
Давайте изучим их работу на следующем примере: выведем полную высоту нашего тестового элемента:
var elem = document.getElementById('elem');
alert('scrollHeight: ' + elem.scrollHeight);
Нажмите на кнопку - и вы увидите результат:
Свойства 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';
Нажмите на кнопку - и вы увидите результат:
Свойство offsetParent
Свойство offsetParent содержит в себе родителя, относительно которого позиционируется элемент. Это будет тег body для статического позиционирования, ближайший позиционированный элемент для других типов позиционирования или ближайшая ячейка таблицы.
Свойства offsetLeft и offsetTop
Свойства offsetLeft и offsetTop содержат в себе позицию в пикселях левого верхнего угла блока относительно его offsetParent.