Понимание offsetWidth, clientWidth, scrollWidth и-Height, соответственно
есть несколько вопросов о StackOverflow относительно offsetWidth/clientWidth / scrollWidth (и-Height, соответственно), но ни один не дает исчерпывающего объяснения того, что это за значения.
кроме того, есть несколько источников в интернете, давая заблуждение или неверную информацию.
можете ли вы дать полное объяснение, включая некоторые визуальные подсказки?
Кроме того, как эти значения могут быть использованы для расчета ширины полосы прокрутки?
4 ответов:
модель CSS box довольно сложна, особенно когда речь заходит о прокрутке контента. Хотя браузер использует значения из вашего CSS для рисования полей, определение всех измерений с помощью JS не является прямым, если у вас есть только CSS.
вот почему каждый элемент имеет шесть свойств DOM для вашего удобства:
offsetWidth,offsetHeight,clientWidth,clientHeight,scrollWidthиscrollHeight. Это атрибуты только для чтения, представляющие текущий визуальный макет, и все они являются чисел (таким образом, возможно, с учетом ошибок округления).давайте рассмотрим их подробно:
offsetWidth,offsetHeight: размер визуального поля, включающего все границы. Можно рассчитать, добавивwidth/heightи отступы и границы, если элементdisplay: blockclientWidth,clientHeight: визуальная часть содержимого коробки, не включая границы или полосы прокрутки, но включает в себя заполнение . Не может быть рассчитан непосредственно от CSS, зависит от размера полосы прокрутки системы.scrollWidth,scrollHeight: размер всего содержимого коробки, включая части, которые в настоящее время скрыты за пределами области прокрутки. Не может быть рассчитан непосредственно из CSS, зависит от содержания.попробуйте:jsFiddle
С
offsetWidthзанимает ширину полосы прокрутки во внимание, мы можем использовать его для расчета ширина полосы прокрутки по формулеscrollbarWidth = offsetWidth - clientWidth - getComputedStyle().borderLeftWidth - getComputedStyle().borderRightWidthк сожалению, мы можем получить ошибки округления, поскольку
offsetWidthиclientWidthвсегда целые числа, в то время как фактические размеры могут быть дробными с уровнями масштабирования, отличными от 1.обратите внимание, что это
scrollbarWidth = getComputedStyle().width + getComputedStyle().paddingLeft + getComputedStyle().paddingRight - clientWidthтут не надежно работать в Chrome, так как Chrome возвращает
widthС полосой прокрутки уже вычитается. (Кроме того, Chrome отображает paddingBottom в нижней части содержимого прокрутки, а другие браузеры не делают)
Если вы хотите использовать ширину прокрутки, чтобы получить "Реал" ШИРИНА/ВЫСОТА СОДЕРЖИМОГО (поскольку содержимое может быть больше, чем CSS-определенная ширина / высота-Box)ширина прокрутки / Высота очень ненадежна поскольку некоторые браузеры, похоже," перемещают " paddingRIGHT & paddingBOTTOM, если контент большой. Затем они помещают прокладки справа / внизу "слишком широкого / высокого содержания" (см. рисунок ниже).
==> поэтому, чтобы получить реальный контент Ширина в некоторых браузерах вы должны вычесть оба заполнения из ширины прокрутки, а в некоторых браузерах вам нужно вычесть только левое заполнение.
Я нашел решение для этого и хотел добавить это в качестве комментария, но не разрешили. Поэтому я сделал снимок и сделал его немного более ясным в отношении "перемещенных прокладок" и "ненадежной ширины прокрутки". в синей области вы найдете мое решение о том, как получить "реальную" ширину контента!
надеюсь, это поможет сделать вещи еще яснее!
Я создал более полную и чистую версию, что некоторые люди могут найти полезным для запоминания того, какое имя соответствует какому значению. Я использовал цветовой код Chrome Dev Tool и метки организованы симметрично, чтобы быстрее подобрать аналогии:
Примечание 1:
clientLeftтакже включает в себя ширину вертикальной прокрутки если направление текста справа-налево (с бар отображается слева в окне тот случай)примечание 2: самая внешняя линия представляет ближайший расположенный родитель (элемент которого
positionсвойство имеет значение, отличное отstaticилиinitial). Таким образом, если прямой контейнер не расположенный элемент, то строка не представляет первый контейнер в иерархии, но другой элемент выше в иерархии. Если нет расположенный родитель найден, браузер приметhtmlилиbodyэлемент, как ссылка
надеюсь, кто-то найдет его полезным, только мои 2 цента ;)
есть хорошая статья о MDN, которая объясняет теорию этих понятий: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements
Это также объясняет важные концептуальные различия между шириной/высотой boundingClientRect и offsetWidth / offsetHeight.
затем, чтобы доказать правильность или неправильность теории, вам нужны некоторые тесты. Вот что я сделал здесь: https://github.com/lingtalfi/dimensions-cheatsheet
это тестирование для chrome53, ff49, safari9, edge13 и ie11.
результаты тестов доказывают, что теория в целом правильно. Для тестов я создал 3 divs, содержащих по 10 абзацев lorem ipsum каждый. К ним был применен некоторый css:
.div1{ width: 500px; height: 300px; padding: 10px; border: 5px solid black; overflow: auto; } .div2{ width: 500px; height: 300px; padding: 10px; border: 5px solid black; box-sizing: border-box; overflow: auto; } .div3{ width: 500px; height: 300px; padding: 10px; border: 5px solid black; overflow: auto; transform: scale(0.5); }и вот результаты:
div1
- offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
- offsetHeight: 330 (chrome53, ff49, safari9, edge13, ie11)
- bcr.ширина: 530 (chrome53, ff49, safari9, edge13, ie11)
bcr.высота: 330 (chrome53, ff49, safari9, edge13, ie11)
clientWidth: 505 (chrome53, ff49, safari9)
- clientWidth: 508 (edge13)
- clientWidth: 503 (ie11)
clientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)
ширина прокрутки: 505 (chrome53, safari9, ff49)
- scrollWidth: 508 (edge13)
- ширина прокрутки: 503 (ie11)
- scrollHeight: 916 (chrome53, safari9)
- scrollHeight: 954 (ff49)
- scrollHeight: 922 (edge13, ie11)
раздел 2
- offsetWidth: 500 (chrome53, ff49, safari9, edge13, ie11)
- offsetHeight: 300 (chrome53, ff49, safari9, edge13, ie11)
- bcr.ширина: 500 (chrome53, ff49, safari9, edge13, ie11)
- bcr.высота: 300 (chrome53, ff49, safari9)
- bcr.высота: 299.9999694824219 (edge13, ie11)
- clientWidth: 475 (chrome53, ff49, safari9)
- clientWidth: 478 (edge13)
- clientWidth: 473 (ie11)
clientHeight: 290 (chrome53, ff49, safari9, edge13, ie11)
ширина прокрутки: 475 (chrome53, safari9, ff49)
- scrollWidth: 478 (edge13)
- ширина прокрутки: 473 (ie11)
- scrollHeight: 916 (chrome53, safari9)
- scrollHeight: 954 (ff49)
- scrollHeight: 922 (edge13, ie11)
div3
- offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
- offsetHeight: 330 (chrome53, ff49, safari9, edge13, ie11)
- bcr.ширина: 265 (chrome53, ff49, safari9, edge13, ie11)
- bcr.рост: 165 (chrome53, ff49, safari9, edge13, ie11)
- clientWidth: 505 (chrome53, ff49, safari9)
- clientWidth: 508 (edge13)
- clientWidth: 503 (ie11)
clientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)
ширина прокрутки: 505 (chrome53, safari9, ff49)
- scrollWidth: 508 (edge13)
- ширина прокрутки: 503 (ie11)
- scrollHeight: 916 (chrome53, safari9)
- scrollHeight: 954 (ff49)
- scrollHeight: 922 (edge13, ie11)
Итак, помимо значения высоты boundingClientRect (299.9999694824219 вместо ожидаемых 300) в edge13 и ie11, результаты подтверждают, что теория, стоящая за этим, работает.
оттуда, вот мое определение этих понятий:
- offsetWidth/offsetHeight: размеры поля границы макета
- boundingClientRect: размеры поля границы рендеринга
- clientWidth/clientHeight: размеры видимой части поля заполнения макета (за исключением полос прокрутки)
- scrollWidth/scrollHeight: размеры поля заполнения макета, если оно не было ограничено полосами прокрутки
примечание: по умолчанию ширина вертикальной полосы прокрутки составляет 12px в edge13, 15px в chrome53, ff49 и safari9 и 17px в ie11 (сделано по измерениям в photoshop со скриншотов и доказано по результатам тестов).
однако в некоторых случаях, возможно, ваше приложение не использует ширину вертикальной полосы прокрутки по умолчанию.
Так, даны определения этих понятий, ширина вертикальной полосы прокрутки должна быть равна (в псевдо-код):
размер макета: offsetWidth-clientWidth - (borderLeftWidth + borderRightWidth)
размер визуализации: boundingClientRect.width-clientWidth - (borderLeftWidth + borderRightWidth)
Примечание, Если вы не понимаете макет против рендеринга, пожалуйста, прочитайте статью mdn.
также, если у вас есть другой браузер (или если вы хотите увидеть результаты тестов на себе), вы можете увидеть мою тестовую страницу здесь: http://codepen.io/lingtalfi/pen/BLdBdL



Comments