Размеры и прокрутка элементов
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/size-and-scroll.
Для того, чтобы показывать элементы на произвольных местах страницы, необходимо во-первых, знать CSS-позиционирование, а во-вторых – уметь работать с «геометрией элементов» из JavaScript.
В этой главе мы поговорим о размерах элементов DOM, способах их вычисления и метриках – различных свойствах, которые содержат эту информацию.
Образец документа
Мы будем использовать для примера вот такой элемент, у которого есть рамка (border), поля (padding), и прокрутка:
У него нет отступов margin , в этой главе они не важны, так как метрики касаются именно размеров самого элемента, отступы в них не учитываются.
Результат выглядит так:
В иллюстрации выше намеренно продемонстрирован самый сложный и полный случай, когда у элемента есть ещё и полоса прокрутки.
В этом случае полоса прокрутки «отодвигает» содержимое вместе с padding влево, отбирая у него место.
Именно поэтому ширина содержимого обозначена как content width и равна 284px , а не 300px , как в CSS.
Точное значение получено в предположении, что ширина полосы прокрутки равна 16px , то есть после её вычитания на содержимое остаётся 300 — 16 = 284px . Конечно, она сильно зависит от браузера, устройства, ОС.
Мы должны в точности понимать, что происходит с размерами элемента при наличии полосы прокрутки, поэтому на картинке выше это отражено.
На рисунке выше поля padding изображены пустыми, но текст там вполне может быть, к примеру, при наличии вертикальной прокрутки.
Метрики
У элементов существует ряд свойств, содержащих их внешние и внутренние размеры. Мы будем называть их «метриками».
Метрики, в отличие от свойств CSS, содержат числа, всегда в пикселях и без единиц измерения на конце.
Вот общая картина:

На картинке все они с трудом помещаются, но, как мы увидим далее, их значения просты и понятны.
Будем исследовать их снаружи элемента и вовнутрь.
offsetParent, offsetLeft/Top
Ситуации, когда эти свойства нужны, можно перечислить по пальцам. Они возникают действительно редко. Как правило, эти свойства используют, потому что не знают средств правильной работы с координатами, о которых мы поговорим позже.
Несмотря на то, что эти свойства нужны реже всего, они – самые «внешние», поэтому начнём с них.
В offsetParent находится ссылка на родительский элемент в смысле отображения на странице.
Уточним, что имеется в виду.
Когда браузер рисует страницу, то он высчитывает дерево расположения элементов, иначе говоря «дерево геометрии» или «дерево рендеринга», которое содержит всю информацию о размерах.
При этом одни элементы естественным образом рисуются внутри других. Но, к примеру, если у элемента стоит position:absolute , то его расположение вычисляется уже не относительно непосредственного родителя parentNode , а относительно ближайшего позиционированного элемента (т.е. свойство position которого не равно static ), или BODY , если такой отсутствует.
Получается, что элемент имеет в дополнение к обычному родителю в DOM – ещё одного «родителя по позиционированию», то есть относительно которого он рисуется. Этот элемент и будет в свойстве offsetParent .
Свойства offsetLeft/Top задают смещение относительно offsetParent .
В примере ниже внутренний <div> имеет DOM-родителя <form> , но offsetParent у него <main> , и сдвиги относительно его верхнего-левого угла будут в offsetLeft/Top :
offsetWidth/Height
Теперь переходим к самому элементу.
Эти два свойства – самые простые. Они содержат «внешнюю» ширину/высоту элемента, то есть его полный размер, включая рамки border .
Для нашего элемента:
- offsetWidth = 390 – внешняя ширина блока, её можно получить сложением CSS-ширины ( 300px , но её часть на рисунке выше отнимает прокрутка, поэтому 284 + 16 ), полей( 2*20px ) и рамок ( 2*25px ).
- offsetHeight = 290 – внешняя высота блока.
Координаты и размеры в JavaScript устанавливаются только для видимых элементов.
Для элементов с display:none или находящихся вне документа дерево рендеринга не строится. Для них метрики равны нулю. Кстати, и offsetParent для таких элементов тоже null .
Это даёт нам замечательный способ для проверки, виден ли элемент:
- Работает, даже если родителю элемента установлено свойство display:none .
- Работает для всех элементов, кроме TR , с которым возникают некоторые проблемы в разных браузерах. Обычно, проверяются не TR , поэтому всё ок.
- Считает элемент видимым, даже если позиционирован за пределами экрана или имеет свойство visibility:hidden .
- «Схлопнутый» элемент, например пустой div без высоты и ширины, будет считаться невидимым.
clientTop/Left
Далее внутри элемента у нас рамки border .
Для них есть свойства-метрики clientTop и clientLeft .
В нашем примере:
- clientLeft = 25 – ширина левой рамки
- clientTop = 25 – ширина верхней рамки
…Но на самом деле они – вовсе не рамки, а отступ внутренней части элемента от внешней.
В чём же разница?
Она возникает тогда, когда документ располагается справа налево (операционная система на арабском языке или иврите). Полоса прокрутки в этом случае находится слева, и тогда свойство clientLeft включает в себя ещё и ширину полосы прокрутки.
clientWidth/Height
Эти свойства – размер элемента внутри рамок border .
Они включают в себя ширину содержимого width вместе с полями padding , но без прокрутки.
На рисунке выше посмотрим вначале на clientHeight , её посчитать проще всего. Прокрутки нет, так что это в точности то, что внутри рамок: CSS-высота 200px плюс верхнее и нижнее поля padding (по 20px ), итого 240px .
На рисунке нижний padding заполнен текстом, но это неважно: по правилам он всегда входит в clientHeight .
Теперь clientWidth – ширина содержимого здесь не равна CSS-ширине, её часть «съедает» полоса прокрутки. Поэтому в clientWidth входит не CSS-ширина, а реальная ширина содержимого 284px плюс левое и правое поля padding (по 20px ), итого 324px .
Если padding нет, то clientWidth/Height в точности равны размеру области содержимого, внутри рамок и полосы прокрутки.
Поэтому в тех случаях, когда мы точно знаем, что padding нет, их используют для определения внутренних размеров элемента.
scrollWidth/Height
Эти свойства – аналоги clientWidth/clientHeight , но с учётом прокрутки.
Свойства clientWidth/clientHeight относятся только к видимой области элемента, а scrollWidth/scrollHeight добавляют к ней прокрученную (которую не видно) по горизонтали/вертикали.
На рисунке выше:
- scrollHeight = 723 – полная внутренняя высота, включая прокрученную область.
- scrollWidth = 324 – полная внутренняя ширина, в данном случае прокрутки нет, поэтому она равна clientWidth .
Эти свойства можно использовать, чтобы «распахнуть» элемент на всю ширину/высоту, таким кодом:
Нажмите на кнопку, чтобы распахнуть элемент:
element.style.height = element.scrollHeight + „px“
scrollLeft/scrollTop
Свойства scrollLeft/scrollTop – ширина/высота невидимой, прокрученной в данный момент, части элемента слева и сверху.
Следующая иллюстрация показывает значения scrollHeight и scrollTop для блока с вертикальной прокруткой.
В отличие от большинства свойств, которые доступны только для чтения, значения scrollLeft/scrollTop можно изменить, и браузер выполнит прокрутку элемента.
При клике на следующий элемент будет выполняться код elem.scrollTop += 10 . Поэтому он будет прокручиваться на 10px вниз:
Не стоит брать width/height из CSS
Мы рассмотрели метрики – свойства, которые есть у DOM-элементов. Их обычно используют для получения их различных высот, ширин и прочих расстояний.
Теперь несколько слов о том, как не надо делать.
Как мы знаем, CSS-высоту и ширину можно установить с помощью elem.style и извлечь, используя getComputedStyle , которые в подробностях обсуждаются в главе Стили и классы.
Получение ширины элемента может быть таким:
Не лучше ли получать ширину так, вместо метрик? Вовсе нет!
Во-первых, CSS-свойства width/height зависят от другого свойства – box-sizing , которое определяет, что такое, собственно, эти ширина и высота. Получается, что изменение box-sizing , к примеру, для более удобной вёрстки, сломает такой JavaScript.
Во-вторых, в CSS свойства width/height могут быть равны auto , например, для инлайн-элемента:
Конечно, с точки зрения CSS размер auto – совершенно нормально, но нам-то в JavaScript нужен конкретный размер в пикселях, который мы могли бы использовать для вычислений. Получается, что в данном случае ширина width из CSS вообще бесполезна.
Есть и ещё одна причина.
Полоса прокрутки – причина многих проблем и недопониманий. Как говорится, «дьявол кроется в деталях». Недопустимо, чтобы наш код работал на элементах без прокрутки и начинал «глючить» с ней.
Как мы говорили ранее, при наличии вертикальной полосы прокрутки, в зависимости от браузера, устройства и операционной системы, она может сдвинуть содержимое.
Получается, что реальная ширина содержимого меньше CSS-ширины. И это учитывают свойства clientWidth/clientHeight .
…Но при этом некоторые браузеры также учитывают это в результате getComputedStyle(elem).width , то есть возвращают реальную внутреннюю ширину, а некоторые – именно CSS-свойство. Эти кросс-браузерные отличия – ещё один повод не использовать такой подход, а использовать свойства-метрики.
Если ваш браузер показывает полосу прокрутки (например, под Windows почти все браузеры так делают), то вы можете протестировать это сами, нажав на кнопку в ифрейме ниже.
У элемента с текстом в стилях указано width:300px .
На момент написания этой главы при тестировании в Chrome под Windows alert выводил 283px , а в Firefox – 300px . При этом оба браузера показывали прокрутку. Это из-за того, что Firefox возвращал именно CSS-ширину, а Chrome – реальную ширину, за вычетом прокрутки.
Описанные разночтения касаются только чтения свойства getComputedStyle(. ).width из JavaScript, визуальное отображение корректно в обоих случаях.
Итого
У элементов есть следующие метрики:
- offsetParent – «родитель по дереву рендеринга» – ближайшая ячейка таблицы, body для статического позиционирования или ближайший позиционированный элемент для других типов позиционирования.
- offsetLeft/offsetTop – позиция в пикселях левого верхнего угла блока, относительно его offsetParent .
- offsetWidth/offsetHeight – «внешняя» ширина/высота блока, включая рамки.
- clientLeft/clientTop – отступ области содержимого от левого-верхнего угла элемента. Если операционная система располагает вертикальную прокрутку справа, то равны ширинам левой/верхней рамки, если же слева (ОС на иврите, арабском), то clientLeft включает в себя прокрутку.
- clientWidth/clientHeight – ширина/высота содержимого вместе с полями padding , но без полосы прокрутки.
- scrollWidth/scrollHeight – ширина/высота содержимого, включая прокручиваемую область. Включает в себя padding и не включает полосы прокрутки.
- scrollLeft/scrollTop – ширина/высота прокрученной части документа, считается от верхнего левого угла.
Все свойства, доступны только для чтения, кроме scrollLeft/scrollTop . Изменение этих свойств заставляет браузер прокручивать элемент.
Размер и координаты элемента
В JavaScript иногда нужно узнать размеры элемента. Использовать для этого CSS свойства неудобно, потому что они не всегда содержат нужную информацию. Для этих целей используются свойства DOM объектов. Они содержат размеры элементов в пикселях. Но они позволяют только получить размеры. Если нужно их изменить, то меняются CSS свойства элемента.
Свойства offsetHeight и offsetWidth содержат общие высоту и ширину элемента вместе с рамкой.
Для примера создадим страницу с таким блоком:
Получим размеры этого блока:
Свойства clientHeight и clientWidth содержат размеры блока без рамки. Они включают содержимое и внутренние отступы.
Эти свойства показывают реальный размер содержимого. Они не всегда соответствуют CSS свойствам элемента. Если элемент имеет полосу прокрутки, то она занимает определённое место внутри содержимого и не входит в свойства clientHeight и clientWidth .
Получим размеры контента для созданного ранее блока:
Координаты элемента
Координаты элементов в JavaScript расчитываются в пикселях и отмеряются от верхнего левого угла. Для получения координат относительно окна браузера используется метод getBoundingClientRect() . Он возвращает объект, содержащий координаты элемента. Объект имеет такие свойства:
top — координата Y верхнего края элемента
left — координата X левого края элемента
bottom — координата Y нижнего края элемента
right — координата X правого края элемента
Эти координаты похожи на те, которые задаются при фиксированном позиционировании элемента. Однако, между ними есть важное отличие. Левые и верхние координаты определяются одинаково, поэтому совпадают. А вот нижние и правые координаты определяются по-разному. При позиционировании правая координата отсчитывается от правого края окна. А при определении координат правая координата отсчитывается от левого края окна. То же самое относится и к нижней координате. При позиционировании отсчёт производится от нижнего края окна, а при определении координат отсчёт производится от верхнего края окна.
Если страница уже прокручена и элемент находится выше или левее окна браузера, то координаты могу иметь отрицательные значения.
Не забывайте, что в большинстве браузеров страница имеет отступы от границ окна. Если эти отступы не отменены, то даже первый элемент на странице сначала имеет не нулевые координаты.
Получить ширину и высоту элемента с помощью JavaScript
В этом посте мы обсудим, как получить ширину и высоту элемента с помощью чистого JavaScript.
В JavaScript есть несколько свойств для получения ширины и высоты элемента. В этом посте представлен обзор некоторых из этих свойств.
1. Использование clientWidth а также clientHeight характеристики
В JavaScript вы можете использовать clientWidth а также clientHeight свойства, чтобы вернуть высоту элемента, включая отступы, но исключая границу, поля или полосы прокрутки. По сути, они возвращают фактическое пространство, используемое отображаемым контентом.
Например, следующий код возвращает ‘520 × 120’.
The scrollWidth а также scrollHeight свойства аналогичны clientWidth а также clientHeight свойства, за исключением того, что они возвращают фактический размер содержимого, независимо от того, сколько на самом деле видно.
2. Использование offsetWidth а также offsetHeight характеристики
В качестве альтернативы, если вам нужно включить границу и полосы прокрутки, вы можете использовать offsetWidth а также offsetHeight характеристики. Они возвращают размеры видимого содержимого элемента, включая отступы, границы и полосы прокрутки. Другими словами, они возвращают общее количество места, которое занимает элемент.
How do I retrieve an HTML element's actual width and height?
Suppose that I have a <div> that I wish to center in the browser’s display (viewport). To do so, I need to calculate the width and height of the <div> element.
What should I use? Please include information on browser compatibility.
16 Answers 16
You should use the .offsetWidth and .offsetHeight properties. Note they belong to the element, not .style .
The .getBoundingClientRect() function returns the dimensions and location of the element as floating-point numbers after performing CSS transforms.
This method will return an object containing the width , height , and some other useful values:
I believe this does not have the issues that .offsetWidth and .offsetHeight do where they sometimes return 0 (as discussed in the comments here)
Another difference is getBoundingClientRect() may return fractional pixels, where .offsetWidth and .offsetHeight will round to the nearest integer.
IE8 Note: getBoundingClientRect does not return height and width on IE8 and below.*
If you must support IE8, use .offsetWidth and .offsetHeight :
Its worth noting that the Object returned by this method is not really a normal object. Its properties are not enumerable (so, for example, Object.keys doesn’t work out-of-the-box.)
- .offsetHeight : https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetHeight
- .offsetWidth : https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetWidth
- .getBoundingClientRect() : https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
NOTE: this answer was written in 2008. At the time the best cross-browser solution for most people really was to use jQuery. I’m leaving the answer here for posterity and, if you’re using jQuery, this is a good way to do it. If you’re using some other framework or pure JavaScript the accepted answer is probably the way to go.
As of jQuery 1.2.6 you can use one of the core CSS functions, height and width (or outerHeight and outerWidth , as appropriate).
Just in case it is useful to anyone, I put a textbox, button and div all with the same css:
I tried it in chrome, firefox and ie-edge, I tried with jquery and without, and I tried it with and without box-sizing:border-box . Always with <!DOCTYPE html>
offsetWidth and offsetHeight return the «total amount of space an element occupies, including the width of the visible content, scrollbars (if any), padding, and border»
clientWidth and clientHeight return «how much space the actual displayed content takes up, including padding but not including the border, margins, or scrollbars»
scrollWidth and scrollHeight return the «actual size of the content, regardless of how much of it is currently visible»
So it depends on whether the measured content is expected to be out of the current viewable area.
It is easy to modify the elements styles but kinda tricky to read the value.
JavaScript can’t read any element style property (elem.style) coming from css(internal/external) unless you use the built in method call getComputedStyle in javascript.
Element: The element to read the value for.
pseudo: A pseudo-element if required, for instance ::before. An empty string or no argument means the element itself.
The result is an object with style properties, like elem.style, but now with respect to all css classes.
For instance, here style doesn’t see the margin:
So modified your javaScript code to include the getComputedStyle of the element you wish to get it’s width/height or other attribute
Computed and resolved values
There are two concepts in CSS:
A computed style value is the value after all CSS rules and CSS inheritance is applied, as the result of the CSS cascade. It can look like height:1em or font-size:125%.
A resolved style value is the one finally applied to the element. Values like 1em or 125% are relative. The browser takes the computed value and makes all units fixed and absolute, for instance: height:20px or font-size:16px. For geometry properties resolved values may have a floating point, like width:50.5px.
A long time ago getComputedStyle was created to get computed values, but it turned out that resolved values are much more convenient, and the standard changed.
So nowadays getComputedStyle actually returns the resolved value of the property.
Please Note:
getComputedStyle requires the full property name
You should always ask for the exact property that you want, like paddingLeft or height or width. Otherwise the correct result is not guaranteed.
For instance, if there are properties paddingLeft/paddingTop, then what should we get for getComputedStyle(elem).padding? Nothing, or maybe a “generated” value from known paddings? There’s no standard rule here.
There are other inconsistencies. As an example, some browsers (Chrome) show 10px in the document below, and some of them (Firefox) – do not: