Розуміння зміщення ширини, ширини клієнта, ширини прокрутки та -висоти відповідно


385

Існує кілька питань щодо StackOverflow щодо offsetWidth / clientWidth / scrollWidth (і -Height відповідно), але жодне не дає вичерпного пояснення, що це за значення.

Також в Інтернеті є кілька джерел, які дають заплутану або неправильну інформацію.

Чи можете ви дати повне пояснення, включаючи деякі візуальні підказки? Крім того, як ці значення можна використовувати для обчислення ширини смуги прокрутки?

Відповіді:


868

Модель CSS box досить складна, особливо якщо мова йде про прокручування вмісту. Хоча браузер використовує значення вашого CSS для малювання вікон, визначення всіх розмірів за допомогою JS не є прямолінійним, якщо у вас є лише CSS.

Саме тому кожен елемент має шість властивостей DOM для вашої зручності: offsetWidth, offsetHeight, clientWidth, clientHeight, scrollWidthі scrollHeight. Це атрибути лише для читання, що представляють поточний візуальний макет, і всі вони є цілими числами (таким чином, можливо, є помилками округлення).

Розглянемо їх детально:

  • offsetWidth, offsetHeight: Розмір візуального поля з усіма рамками. Можна обчислити, додавши width/ heightта прокладки та рамки, якщо елемент маєdisplay: block
  • clientWidth, clientHeight: Візуальна частина вмісту поля, не включає рамки або смуги прокрутки, але включає в себе набивання. Не може бути обчислений безпосередньо з CSS, залежить від розміру смуги прокрутки системи.
  • scrollWidth, scrollHeight: Розмір усього вмісту поля, включаючи частини, які зараз приховані поза зоною прокрутки. Не може бути обчислений безпосередньо з CSS, залежить від вмісту.

Модель коробки CSS2

Спробуйте: 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 в нижній частині вмісту прокрутки, тоді як інші веб-переглядачі цього не роблять)


27
Для тих, хто шукає більш дрібну деталізацію, ніж цілі числа, використовуйте element.getBoundingClientRect()(див. Примітку на адресу developer.mozilla.org/en-US/docs/Web/API/Element.clientWidth )
Anson Kao

1
Зауважте, що залежно від вашого макета, ширина прокрутки та прокручування може бути дуже корисною для отримання розміру ваших псевдоелементів :: до та :: після.
Девід

Також було б корисно пояснити, як вони відносяться до naturalWidthтаnaturalHeight
YakovL

чому scrollHeightвключає, padding-bottomале scrollWidthне включаєpadding-right
JunGor

clientWidthдля document.documentElement.clientWidthвідрізняється , як здається, включають в себе padding, bordersіmargin
Drenai

49

Я створив більш вичерпну та більш чисту версію, що деяким людям може бути корисною для запам’ятовування, яке ім’я відповідає якому значенню. Я використовував колірний код інструмента Chrome Dev, а мітки розташовані симетрично, щоб швидше підбирати аналогії:

введіть тут опис зображення

  • Примітка 1: clientLeftтакож включає ширину вертикальної смуги прокрутки, якщо напрямок тексту встановлено справа наліво (оскільки в цьому випадку смужка відображається зліва)

  • Примітка 2: Найбільш зовнішня лінія являє собою найближчий розміщений батьківський елемент (елемент, positionвластивість якого встановлено на значення, відмінне від staticабо initial). Таким чином, якщо прямий контейнер не є позиціонованим елементом, то рядок не представляє перший контейнер в ієрархії, а інший елемент, що знаходиться вище в ієрархії. Якщо батьківський позиціонер не знайдений, браузер візьме елемент htmlабо bodyелемент як посилання


Сподіваюся, хтось вважає це корисним, лише мої 2 копійки;)


30

Якщо ви хочете використовувати ширину прокрутки, щоб отримати " РЕАЛЬНУ " ЗМІСТ ШИРОТУ / ВИСОКУ (оскільки вміст може бути ВЕЛИЧЕшим, ніж визначена css ширина / висота-Box), то ширина прокрутки / висота дуже НЕВЕРІТАЛЬНА, як здається, що деякий браузер "ПОДІЛИТИ" paddingRIGHT & paddingBOTTOM, якщо вміст великий. Потім вони розміщують прокладки на ПРАВО / БОТЬ «занадто широкий / високий вміст» (див. Малюнок нижче).

==> Тому, щоб отримати РЕАЛЬНУ ВИСОКУ ВМІСТУ в деяких браузерах, ви повинні підкреслити БОТИ підкладки з ширини прокрутки, а в деяких браузерах потрібно лише піддавати ліву підкладку.

Я знайшов рішення для цього і хотів додати це як коментар, але не було дозволено. Тож я сфотографував і зробив це трохи зрозуміліше щодо "переміщених прокладок" та "ненадійної ширини прокрутки". У СВІТІЙ ОБЛАСТІ ви знайдете моє рішення про те, як отримати "РЕАЛЬНУ" ЗМІСТ ЗМІСТУ!

Сподіваюсь, це допомагає зробити речі ще зрозумілішими!

введіть тут опис зображення


13

Існує гарна стаття про MDN, яка пояснює теорію цих концепцій: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements

Він також пояснює важливі концептуальні відмінності між шириною / висотою limitingClientRect та offsetWidth / offsetHeight.

Потім, щоб довести теорію правильно чи неправильно, потрібні кілька тестів. Ось що я тут зробив: https://github.com/lingtalfi/dimensions-cheatsheet

Це тестування на chrome53, ff49, safari9, edge13 та ie11.

Результати тестів доводять, що теорія загалом права. Для тестів я створив 3 диви, що містять 10 абзаців з iremum. До них застосовано деякий 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

    • ширина зміщення: 530 (chrome53, ff49, safari9, edge13, ie11)
    • зсувВисота: 330 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.width: 530 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.висота: 330 (chrome53, ff49, safari9, edge13, ie11)

    • Ширина клієнта: 505 (chrome53, ff49, safari9)

    • Ширина клієнта: 508 (край13)
    • Ширина клієнта: 503 (тобто11)
    • Висота клієнта: 320 (chrome53, ff49, safari9, edge13, ie11)

    • ширина прокрутки: 505 (chrome53, safari9, ff49)

    • ширина прокрутки: 508 (край13)
    • ширина прокрутки: 503 (тобто11)
    • висота прокрутки: 916 (chrome53, safari9)
    • висота прокрутки: 954 (ff49)
    • Висота прокрутки: 922 (край13, тобто11)
  • div2

    • ширина зміщення: 500 (chrome53, ff49, safari9, edge13, ie11)
    • зміщенняВисота: 300 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.width: 500 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.висота: 300 (chrome53, ff49, safari9)
    • bcr.зрост: 299.9999694824219 (край13, тобто11)
    • Ширина клієнта: 475 (chrome53, ff49, safari9)
    • Ширина клієнта: 478 (край13)
    • Ширина клієнта: 473 (тобто11)
    • Висота клієнта: 290 (chrome53, ff49, safari9, edge13, ie11)

    • ширина прокрутки: 475 (chrome53, safari9, ff49)

    • ширина прокрутки: 478 (край13)
    • ширина прокрутки: 473 (тобто11)
    • висота прокрутки: 916 (chrome53, safari9)
    • висота прокрутки: 954 (ff49)
    • Висота прокрутки: 922 (край13, тобто11)
  • div3

    • ширина зміщення: 530 (chrome53, ff49, safari9, edge13, ie11)
    • зсувВисота: 330 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.width: 265 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.height: 165 (chrome53, ff49, safari9, edge13, ie11)
    • Ширина клієнта: 505 (chrome53, ff49, safari9)
    • Ширина клієнта: 508 (край13)
    • Ширина клієнта: 503 (тобто11)
    • Висота клієнта: 320 (chrome53, ff49, safari9, edge13, ie11)

    • ширина прокрутки: 505 (chrome53, safari9, ff49)

    • ширина прокрутки: 508 (край13)
    • ширина прокрутки: 503 (тобто11)
    • висота прокрутки: 916 (chrome53, safari9)
    • висота прокрутки: 954 (ff49)
    • Висота прокрутки: 922 (край13, тобто11)

Так, крім значення висоти граничногоClientRect (299.9999694824219 замість очікуваних 300) у краю13 та 11, результати підтверджують, що теорія, що стоїть за цим, працює.

Звідси, ось моє визначення цих понять:

  • offsetWidth / offsetHeight: розміри рамки рамки макета
  • borderingClientRect: розміри вікна рамки візуалізації
  • clientWidth / clientHeight: розміри видимої частини коробки для накладки макета (за винятком смуг прокрутки)
  • scrollWidth / scrollHeight: розміри поля обкладки для макета, якщо його не обмежували смуги прокрутки

Примітка: ширина смуги прокрутки за замовчуванням становить 12 пікселів у краю13, 15 пікселів у хромі53, ff49 та safari9 та 17 пікселів у ie11 (зроблено за допомогою вимірювань у фотошопі зі скріншотів і доведено правильно за результатами тестів).

Однак у деяких випадках можливо ваша програма не використовує вертикальну ширину смуги прокрутки за замовчуванням.

Отже, враховуючи визначення цих понять, ширина вертикальної смуги прокрутки повинна бути рівною (у псевдокоді):

  • розмір макета: offsetWidth - clientWidth - (borderLeftWidth + borderRightWidth)

  • розмір візуалізації: limitingClientRect.width - clientWidth - (borderLeftWidth + borderRightWidth)

Зауважте, якщо ви не розумієте макет та рендерінг, прочитайте статтю mdn.

Крім того, якщо у вас інший браузер (або якщо ви хочете побачити результати тестів для себе), ви можете переглянути мою тестову сторінку тут: http://codepen.io/lingtalfi/pen/BLdBdL

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.