Model pudełkowy CSS jest dość skomplikowany, szczególnie jeśli chodzi o przewijanie treści. Podczas gdy przeglądarka używa wartości z twojego CSS do rysowania ramek, określenie 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 wygody: offsetWidth
, offsetHeight
, clientWidth
, clientHeight
, scrollWidth
i scrollHeight
. Są to atrybuty tylko do odczytu reprezentujące bieżący układ wizualny, a wszystkie z nich są liczbami całkowitymi (w związku z tym mogą wystąpić błędy zaokrąglania).
Przejrzyjmy je szczegółowo:
offsetWidth
, offsetHeight
: Rozmiar pola wizualnego zawierającego wszystkie obramowania. Można obliczyć, dodając width
/ height
i wypełnienia i obramowania, jeśli element madisplay: block
clientWidth
, clientHeight
: Część wizualna zawartości pola, nie zawierająca ramek ani pasków przewijania, ale obejmuje dopełnienie. Nie można obliczyć bezpośrednio z CSS, zależy od rozmiaru paska przewijania systemu.
scrollWidth
, scrollHeight
: Rozmiar całej zawartości pola, 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.
Ponieważ offsetWidth
uwzględnia szerokość paska przewijania, możemy go użyć do obliczenia szerokości paska przewijania za pomocą formuły
scrollbarWidth = offsetWidth - clientWidth - getComputedStyle().borderLeftWidth - getComputedStyle().borderRightWidth
Niestety mogą wystąpić błędy zaokrąglania, ponieważ offsetWidth
i clientWidth
zawsze są liczbami całkowitymi, podczas gdy rzeczywiste rozmiary mogą być ułamkowe przy poziomach powiększenia innych niż 1.
Zauważ, że to
scrollbarWidth = getComputedStyle().width + getComputedStyle().paddingLeft + getComputedStyle().paddingRight - clientWidth
ma nie działać niezawodnie w Chrome, Chrome, ponieważ wraca width
z przewijania już odjąć. (Ponadto Chrome renderuje paddingBottom na dole przewijanej zawartości, podczas gdy inne przeglądarki tego nie robią)
element.getBoundingClientRect()
(patrz uwaga na developer.mozilla.org/en-US/docs/Web/API/Element.clientWidth )naturalWidth
inaturalHeight
scrollHeight
zawiera,padding-bottom
alescrollWidth
nie obejmujepadding-right
clientWidth
zadocument.documentElement.clientWidth
to różne, jak to wydaje się zawieraćpadding
,borders
orazmargin
Stworzyłem bardziej kompleksową i czystszą wersję, która może być przydatna dla niektórych osób, pamiętając, która nazwa odpowiada której wartości. Użyłem kodu koloru Chrome Dev Tool, a etykiety są zorganizowane symetrycznie, aby szybciej odbierać analogie:
Uwaga 1:
clientLeft
obejmuje również szerokość pionowego paska przewijania, jeśli kierunek tekstu jest ustawiony od prawej do lewej (w takim przypadku pasek jest wyświetlany w lewo)Uwaga 2: najbardziej zewnętrzna linia reprezentuje najbliżej położonego rodzica (element, którego
position
właściwość jest ustawiona na wartość inną niżstatic
lubinitial
). Zatem jeśli bezpośredni kontener nie jest elementem pozycjonowanym , to linia nie reprezentuje pierwszego kontenera w hierarchii, ale inny element wyżej w hierarchii. Jeśli nie zostanie znaleziony element nadrzędny pozycjonowany , przeglądarka przyjmie elementhtml
lubbody
jako odniesienieMam nadzieję, że ktoś uzna to za przydatne, tylko moje 2 centy;)
źródło
Jeśli chcesz użyć scrollWidth, aby uzyskać „PRAWDZIWĄ” SZEROKOŚĆ / WYSOKOŚĆ TREŚCI (ponieważ treść może być WIĘKSZA niż zdefiniowana przez css szerokość / wysokość-Box), scrollWidth / Height jest bardzo NIEZAWODNA, ponieważ niektóre przeglądarki wydają się „PRZESUWAĆ” paddingRIGHT & paddingBOTTOM, jeśli treść jest za duża. Następnie umieszczają wypełnienia po PRAWEJ / DOLNEJ „zbyt szerokiej / wysokiej zawartości” (patrz obrazek poniżej).
==> Dlatego, aby uzyskać PRAWDZIWĄ SZEROKOŚĆ TREŚCI w niektórych przeglądarkach, musisz odjąć OBA wypełnienia od szerokości przewijania, aw niektórych przeglądarkach musisz tylko odjąć LEWĄ wypełnienie.
Znalazłem rozwiązanie tego problemu i chciałem dodać to jako komentarz, ale nie było to dozwolone. Zrobiłem więc zdjęcie i uczyniłem je nieco jaśniejszym w odniesieniu do „ruchomych podkładek” i „niewiarygodnego scrollWidth”. W NIEBIESKIEJ OBSZARZE znajdziesz moje rozwiązanie, jak uzyskać „PRAWDZIWĄ” SZEROKOŚĆ TREŚCI!
Mam nadzieję, że dzięki temu wszystko będzie jeszcze wyraźniejsze!
źródło
Istnieje dobry artykuł na temat MDN, który wyjaśnia teorię tych pojęć: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements
Wyjaśnia także ważne koncepcyjne różnice między szerokością / wysokością boundingClientRect a offsetWidth / offsetHeight.
Następnie, aby udowodnić, że teoria jest dobra lub zła, potrzebujesz testów. To właśnie zrobiłem tutaj: https://github.com/lingtalfi/dimensions-cheatsheet
Testuje pod kątem chrome53, ff49, safari9, edge13 i ie11.
Wyniki testów dowodzą, że teoria jest ogólnie słuszna. Do testów stworzyłem 3 div zawierające po 10 akapitów lorem ipsum. Zastosowano do nich trochę css:
A oto wyniki:
div1
bcr.height: 330 (chrome53, ff49, safari9, edge13, ie11)
clientWidth: 505 (chrome53, ff49, safari9)
clientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)
scrollWidth: 505 (chrome53, safari9, ff49)
div2
clientHeight: 290 (chrome53, ff49, safari9, edge13, ie11)
scrollWidth: 475 (chrome53, safari9, ff49)
div3
clientHeight: 320 (chrome53, ff49, safari9, edge13, ie11)
scrollWidth: 505 (chrome53, safari9, ff49)
Tak więc, oprócz wartości wysokości boundingClientRect (299,9999694824219 zamiast oczekiwanych 300) w edge13 i ie11, wyniki potwierdzają, że teoria leżąca u podstaw tego działania działa.
Stamtąd oto moja definicja tych pojęć:
Uwaga: domyślna szerokość pionowego paska przewijania wynosi 12px w edge13, 15px w chrome53, ff49 i safari9 oraz 17px w ie11 (wykonane na podstawie pomiarów w Photoshopie ze zrzutów ekranu i potwierdzone bezpośrednio na podstawie wyników testów).
Jednak w niektórych przypadkach być może Twoja aplikacja nie używa domyślnej szerokości pionowego paska przewijania.
Biorąc pod uwagę definicje tych pojęć, szerokość pionowego paska przewijania powinna być równa (w pseudokodzie):
wymiar układu: offsetWidth - clientWidth - (borderLeftWidth + borderRightWidth)
wymiar renderowania: boundingClientRect.width - clientWidth - (borderLeftWidth + borderRightWidth)
Uwaga: jeśli nie rozumiesz układu vs renderowania, przeczytaj artykuł mdn.
Ponadto, 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
źródło