Zrozumienie odpowiednio offsetWidth, clientWidth, scrollWidth i-Height

W Stoskoverflow jest kilka pytań dotyczących offsetWidth/clientWidth/scrollWidth (oraz-Height, odpowiednio), ale żadne z nich nie wyjaśnia wyczerpująco, czym są te wartości.

Ponadto, istnieje kilka źródeł w Internecie podając mylące lub nieprawidłowe informacje.

Czy możesz podać pełne wyjaśnienie, w tym wskazówki wizualne? W jaki sposób można również wykorzystać te wartości do obliczania szerokości paska przewijania?

 296
Author: user123444555621, 2014-01-11

4 answers

Model pudełkowy CSS jest dość skomplikowany, szczególnie jeśli chodzi o przewijanie zawartości. Podczas gdy przeglądarka używa wartości z twojego CSS do rysowania pól, określanie wszystkich wymiarów za pomocą JS nie jest proste, jeśli masz tylko CSS.

Dlatego każdy element ma sześć właściwości DOM dla Twojej wygody: offsetWidth, offsetHeight, clientWidth, clientHeight, scrollWidth i scrollHeight. Są to atrybuty tylko do odczytu reprezentujące aktualny układ wizualny, a wszystkie z nich są liczbami całkowitymi (Tak więc prawdopodobnie z powodu błędów zaokrąglania).

Przejrzyjmy je szczegółowo:

  • offsetWidth, offsetHeight: wielkość pola wizualnego obejmującego wszystkie granice. Można obliczyć dodając width/height oraz paddings i borders, jeśli element ma display: block
  • clientWidth, clientHeight: wizualna część zawartości pudełka, nie obejmuje obramowań ani pasków przewijania, ale zawiera wypełnienia . Nie można obliczyć bezpośrednio z CSS, zależy od rozmiaru paska przewijania systemu.
  • scrollWidth, scrollHeight: Rozmiar całej zawartości pudełka, w tym części, które są obecnie ukryte poza obszarem przewijania. Nie można obliczyć bezpośrednio z CSS, zależy od zawartości.

Model pudełkowy CSS2

Wypróbuj: jsFiddle


Ponieważ offsetWidth uwzględnia Szerokość paska przewijania, możemy użyć go do obliczenia szerokości paska przewijania za pomocą wzoru

scrollbarWidth = offsetWidth - clientWidth - getComputedStyle().borderLeftWidth - getComputedStyle().borderRightWidth

Niestety, mogą pojawić się błędy zaokrąglania, ponieważ offsetWidth i clientWidth są zawsze liczby całkowite, podczas gdy rzeczywiste rozmiary mogą być ułamkowe z poziomami powiększenia innymi niż 1.

Zauważ, że to

scrollbarWidth = getComputedStyle().width + getComputedStyle().paddingLeft + getComputedStyle().paddingRight - clientWidth

Czy Nie działa niezawodnie w Chrome, ponieważ Chrome zwraca width z odjętym paskiem przewijania. Chrome wyświetla również paddingBottom na dole zawartości przewijania, podczas gdy inne przeglądarki tego nie robią.]}

 694
Author: user123444555621,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-17 08:23:43

Jeśli chcesz użyć scrollWidth, aby uzyskać "REAL" CONTENT WIDTH / HEIGHT (ponieważ zawartość może być większa niż okno width/height zdefiniowane przez css) scrollWidth / Height jest bardzo zawodne Jak niektóre przeglądarki wydają się "przenieść" paddingRIGHT & paddingBOTTOM jeśli zawartość jest duża. Następnie umieszczają podkładki po prawej / na dole " zbyt szerokiej / wysokiej zawartości "(patrz zdjęcie poniżej).

==> Dlatego, aby uzyskać rzeczywistą szerokość zawartości w niektórych przeglądarkach masz aby odjąć oba paddingi od przewijania, a w niektórych przeglądarkach wystarczy odjąć lewe Padding.

Znalazłem na to rozwiązanie i chciałem dodać to jako komentarz, ale nie było dozwolone. Zrobiłem więc zdjęcie i uczyniłem je nieco wyraźniejszym w odniesieniu do" przesuniętych paddingów "i"zawodnego przewijania". W niebieskim obszarze znajdziesz moje rozwiązanie, jak uzyskać "prawdziwą" szerokość treści!

Hope this helps to make things even jaśniej!

Tutaj wpisz opis obrazka

 29
Author: Manny_user3297459,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-12 13:07:56

Stworzyłem bardziej kompleksową i czystszą wersję, która może być przydatna dla niektórych osób do zapamiętywania, która nazwa odpowiada jakiej wartości. Użyłem kodu kolorów Chrome Dev Tool i etykiety są zorganizowane symetrycznie, aby szybciej odbierać analogie: {]}

Tutaj wpisz opis obrazka

  • Uwaga 1: clientLeft obejmuje również szerokość pionowego przewijania bar, jeśli Kierunek tekstu jest ustawiony na prawo-do-lewej (ponieważ pasek jest wyświetlany po lewej stronie w tym case)

  • Uwaga 2: najbardziej wysunięta linia reprezentuje najbliższą pozycjonowanie rodzic (element, którego właściwość position jest ustawiona na wartość inną niż static lub initial). Tak więc, jeśli bezpośredni kontener nie jest pozycjonowanie element, wtedy linia nie przedstawia pierwszego kontenera w hierarchii, ale kolejny element wyżej w hierarchii. Jeśli nie pozycjonowanie rodzica znajduje się, przeglądarka zajmie html lub body element jako odniesienie


Mam nadzieję, że komuś się przyda, tylko moje 2 grosze ;)

 29
Author: Lual,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-30 03:18:25

Jest dobry artykuł na temat MDN, który wyjaśnia teorię stojącą za tymi pojęciami: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements

Wyjaśnia również istotne różnice koncepcyjne między szerokością/wysokością boundingClientRect a offsetWidth/offsetHeight.

Następnie, aby udowodnić teorię dobrze lub źle, potrzebujesz testów. To właśnie zrobiłem.: https://github.com/lingtalfi/dimensions-cheatsheet

Testuje chrome53, ff49, safari9, edge13 i ie11.

Wyniki testów dowodzą, że teoria jest ogólnie słuszna. Na potrzeby testów stworzyłem 3 divy zawierające po 10 akapitów lorem ipsum każdy. Niektóre css zostały do nich zastosowane:

.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);
}

A oto wyniki:

  • Div1

    • offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
    • offsetHeight: 330 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.szerokość: 530 (chrome53, ff49, safari9, edge13, ie11)
    • Bcr.Wysokość: 330 (chrome53, ff49, safari9, edge13, ie11)

    • ClientWidth: 505 (chrome53, ff49, safari9)

    • clientWidth: 508 (edge13)
    • clientWidth: 503 (ie11)
    • ClientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)

    • ScrollWidth: 505 (chrome53, safari9, ff49)

    • scrollWidth: 508 (edge13)
    • scrollWidth: 503 (ie11)
    • scrollHeight: 916 (chrome53, safari9)
    • scrollHeight: 954 (ff49)
    • scrollHeight: 922 (edge13, ie11)
  • Div2

    • offsetWidth: 500 (chrome53, ff49, safari9, edge13, ie11)
    • offsetHeight: 300 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.szerokość: 500 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.wysokość: 300 (chrome53, ff49, safari9)
    • bcr.wysokość: 299.9999694824219 (edge13, ie11)
    • clientWidth: 475 (chrome53, ff49, safari9)
    • clientWidth: 478 (edge13)
    • clientWidth: 473 (ie11)
    • ClientHeight: 290 (chrome53, ff49, safari9, edge13, ie11)

    • ScrollWidth: 475 (chrome53, safari9, ff49)

    • scrollWidth: 478 (edge13)
    • scrollWidth: 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.szerokość: 265 (chrome53, ff49, safari9, edge13, ie11)
    • bcr.wysokość: 165 (chrome53, ff49, safari9, edge13, ie11)
    • clientWidth: 505 (chrome53, ff49, safari9)
    • clientWidth: 508 (edge13)
    • clientWidth: 503 (ie11)
    • ClientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)

    • ScrollWidth: 505 (chrome53, safari9, ff49)

    • scrollWidth: 508 (edge13)
    • scrollWidth: 503 (ie11)
    • scrollHeight: 916 (chrome53, safari9)
    • scrollHeight: 954 (ff49)
    • scrollHeight: 922 (edge13, ie11)

Więc, oprócz wartości wysokości boundingClientRect (299.9999694824219 zamiast oczekiwanego 300) W edge13 i ie11, wyniki potwierdzają, że teoria za tym działa.

Stąd moja definicja tych pojęć:
  • offsetWidth/ offsetHeight: wymiary ramki układu
  • boundingClientRect: wymiary ramki renderującej
  • clientWidth/clientHeight: wymiary widocznej części pola wypełnienia układu (z wyłączeniem pasków przewijania)
  • scrollWidth / scrollHeight: wymiary pola wypełnienia układu, jeśli nie było ograniczone paskami przewijania

Uwaga: domyślna szerokość pionowego paska przewijania wynosi 12px w edge13, 15px w chrome53, ff49 i safari9 oraz 17px w ie11(wykonane przez pomiary w Photoshopie z zrzutów ekranu i potwierdzone wynikami testów).

Jednak w niektórych przypadkach może Twoja aplikacja nie używa domyślnej szerokości pionowego paska przewijania.

Więc, biorąc pod uwagę definicje tych pojęć, szerokość pionowego paska przewijania powinna być równa (w pseudo kod): {]}

  • Wymiary układu: offsetWidth-clientWidth - (borderLeftWidth + borderRightWidth)

  • Wymiar renderowania: boundingClientRect.szerokość-clientWidth - (borderLeftWidth + borderRightWidth)

Uwaga, Jeśli nie rozumiesz układu i renderowania, przeczytaj artykuł mdn.

Również, jeśli masz inną przeglądarkę (lub jeśli chcesz zobaczyć wyniki testów dla siebie), możesz zobaczyć moją stronę testową tutaj: http://codepen.io/lingtalfi/pen/BLdBdL

 10
Author: ling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-05 12:58:56