问题描述
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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。