問題描述
StackOverflow 有關於 offsetWidth /clientWidth /scrollWidth(分別為-Height) 的幾個問題,但是沒有給出這些值的全面解釋。
此外,網絡上有幾個來源提供混淆或不正確的信息。
你能給出一個完整的解釋,包括一些視覺提示嗎?此外,如何使用這些值來計算滾動條寬度?
最佳解決方案
CSS 框模型相當複雜,特別是在滾動內容時。當瀏覽器使用 CSS 中的值繪製框時,如果您只有 CSS,則使用 JS 確定所有尺寸不是 straight-forward 。
這就是為什麼每個元素有六個 DOM 屬性為您方便:offsetWidth,offsetHeight,clientWidth,clientHeight,scrollWidth 和 scrollHeight 。這些是表示當前視覺佈局的 read-only 屬性,它們都是整數 (因此可能會受到舍入誤差的影響) 。
讓我們詳細瞭解一下:
-
offsetWidth,offsetHeight:包含所有邊框的視覺盒的大小。可以通過添加width/height和填充邊框來計算,如果元素具有display: block -
clientWidth,clientHeight:框內容的可視部分,不包括邊框或滾動條,但包括填充。不能直接從 CSS 計算,取決於系統的滾動條大小。 -
scrollWidth,scrollHeight:所有框的內容的大小,包括當前隱藏在滾動區域之外的部分。不能直接從 CSS 計算,取決於內容。
嘗試一下:jsFiddle
由於 clientWidth 考慮到滾動條寬度,因此可以通過公式計算滾動條的寬度
scrollbarWidth = offsetWidth - clientWidth - getComputedStyle().borderLeftWidth - getComputedStyle().borderRightWidth
不幸的是,我們可能會收到四捨五入的錯誤,因為 offsetWidth 和 clientWidth 總是整數,而實際的大小可能是小於 1 的縮放比例。
注意這個
scrollbarWidth = getComputedStyle().width + getComputedStyle().paddingLeft + getComputedStyle().paddingRight - clientWidth
在 Chrome 中無法可靠地運行,因為 Chrome 返回 width,滾動條已經被減除。 (此外,Chrome 會將 paddingBottom 放置在滾動內容的底部,而其他瀏覽器則不會)
次佳解決方案
如果要使用 scrollWidth 來獲取”REAL” 內容寬度/高度 (因為內容可能比 css-defined 寬度/height-Box 大),scrollWidth /Height 是非常不可靠的,因為一些瀏覽器似乎是”MOVE” 的 paddingRIGHT& 如果內容大到 paddingBOTTOM 。然後他們將填充物放在 「太寬/高含量」 的右/底部 (見下圖) 。
==> 因此,為了在某些瀏覽器中獲得 REAL CONTENT WIDTH,您必須從滾動寬度中減去 BOTH padding,而在某些瀏覽器中,您只需減去 LEFT Padding 。
我找到了一個解決方案,並希望將其添加為評論,但不允許。所以我拍了照片,並在”moved paddings” 和”unreliable scrollWidth” 方面更清晰一些。在藍色區域,您可以找到我如何獲得”REAL” 內容寬度的解決方案!
希望這有助於使事情更加清晰!

第三種解決方案
有一篇關於 MDN 的文章解釋了這些概念背後的理論:https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements
它還解釋了 boundingClientRect 的 width /height 與 offsetWidth /offsetHeight 之間的重要概念差異。
那麼,為了證明這個理論是對還是錯,你需要一些考驗。這就是我在這裏做的:https://github.com/lingtalfi/dimensions-cheatsheet
它正在測試 chrome53,ff49,safari9,edge13 和 ie11 。
測試結果證明瞭這個理論是正確的。對於測試,我創建了 3 個 div,每個 div 包含 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.width:530(chrome53,ff49,safari9,edge13,ie11)
-
bcr.height: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.width:500(chrome53,ff49,safari9,edge13,ie11)
-
bcr.height:300(chrome53,ff49,safari9)
-
bcr.height: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.width:265(chrome53,ff49,safari9,edge13,ie11)
-
bcr.height: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)
-
所以,除了 edgeClientRect 的 height 值 (299.9999694824219 而不是預期的 300),edge13 和 ie11 中,結果證實了這個理論背後的理論。
從那裏,這裏是我對這些概念的定義:
-
offsetWidth /offsetHeight:佈局邊框框的尺寸
-
boundingClientRect:渲染邊框框的尺寸
-
clientWidth /clientHeight:佈局填充框的可見部分的尺寸 (不包括滾動條)
-
scrollWidth /scrollHeight:如果不受滾動條約束,則會使用佈局填充框的尺寸
注意:默認垂直滾動條的寬度在 edge13 中為 12px,在 chrome53,ff49 和 safari9 中為 15px,在 ie11 中為 17px(通過在 photoshop 中的屏幕截圖進行測量,並通過測試結果證明) 。
但是,在某些情況下,也許您的應用程序不會使用默認的垂直滾動條的寬度。
因此,給定這些概念的定義,垂直滾動條的寬度應等於 (在偽代碼中):
-
佈局尺寸:offsetWidth – clientWidth – (borderLeftWidth + borderRightWidth)
-
渲染維度:boundingClientRect.width – clientWidth – (borderLeftWidth + borderRightWidth)
注意,如果您不明白布局與渲染,請閲讀 mdn 文章。
此外,如果您有其他瀏覽器 (或者您想要查看自己的測試結果),您可以在這裏看到我的測試頁:http://codepen.io/lingtalfi/pen/BLdBdL
參考文獻
注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。
