分别了解offsetWidth,clientWidth,scrollWidth和-Height

有关StackOverflow关于offsetWidth / clientWidth / scrollWidth(和-Height,分别)的几个问题,但没有给出这些值是什么的全面解释。

此外,网上有几个来源给出混淆或不正确的信息。

你能给出一个完整的解释,包括一些视觉提示? 另外,如何使用这些值来计算滚动条宽度?

CSS框模型相当复杂,特别是在滚动内容时。 虽然浏览器使用CSS中的值来绘制框,但如果仅使用CSS,则使用JS确定所有的尺寸并不是直接的。

这就是为什么每个元素有六个DOM属性为您的方便: offsetWidthoffsetHeightclientWidthclientHeightscrollWidthscrollHeight 。 这些是表示当前可视布局的只读属性,它们都是整数 (因此可能会出现舍入误差)。

我们来详细的介绍一下:

  • offsetWidthoffsetHeight :包含所有边框的可视化框的大小。 可以通过添加width / height和填充和边框来计算,如果元素具有display: block
  • clientWidthclientHeight :框内容的可视部分,不包括边框或滚动条,但包括填充。 无法直接从CSS计算,取决于系统的滚动条大小。
  • scrollWidthscrollHeight :框的所有内容的大小,包括当前隐藏在滚动区域之外的部分。 不能直接从CSS计算,取决于内容。

CSS2框模型

试试看: jsFiddle


由于offsetWidth考虑了滚动条的宽度,我们可以用它来通过公式计算滚动条的宽度

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

不幸的是,我们可能会得到四舍五入的错误,因为offsetWidthclientWidth总是整数,而实际的大小可能是分数,其缩放级别不是1。

请注意这一点

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

在Chrome中无法可靠运行,因为Chrome已经减less了滚动条的width 。 (另外,Chrome会将paddingBottom呈现到滚动内容的底部,而其他浏览器则不会)

如果你想使用scrollWidth获得“真实”的 内容宽度/高度 (因为内容可以比css定义的宽度/高度框大) scrollWidth /高度是非常不可靠的,因为一些浏览器似乎“移动”paddingRIGHT &paddingBOTTOM如果内容很大。 然后他们把垫子放在“太宽/高含量”的右边/底部(见下图)。

==>因此,要在某些浏览器中获得实际内容宽度,您必须从滚动宽度中减去两个填充,而在某些浏览器中,只需减去左填充即可。

我find了这个解决scheme,并希望添加这个作为评论,但不被允许。 所以我拍了这张照片,并且在“移动的填充”和“不可靠的scrollWidth”方面做了一些更清晰的处理。 在蓝色区域,您可以find我的解决scheme,以获取“真实”内容宽度!

希望这有助于使事情更清晰!

在这里输入图像说明

MDN上有一篇很好的文章解释了这些概念背后的理论: https : //developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Det​​ermining_the_dimensions_of_elements

它还解释了boundingClientRect的宽度/高度与offsetWidth / offsetHeight之间的重要概念差异。

那么,为了certificate理论的正确与否,你需要一些testing。 这就是我在这里所做的: https : //github.com/lingtalfi/dimensions-cheatsheet

它正在testingchrome53,ff49,safari9,edge13和ie11。

testing的结果certificate了这个理论是正确的。 为了testing,我创build了3个div,每个包含10个lipsum段落。 一些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)

因此,除了edge13和ie11中boundingClientRect的高度值(299.9999694824219而不是预期的300)之外,结果证实了这个理论背后的理论。

从那里,这里是我对这些概念的定义:

  • offsetWidth / offsetHeight:布局边框的尺寸
  • boundingClientRect:渲染边框的尺寸
  • clientWidth / clientHeight:布局填充框的可见部分的尺寸(不包括滚动条)
  • scrollWidth / scrollHeight:布局填充框的尺寸(如果不受滚动条的限制)

注意:在edge13中默认的垂直滚动条宽度是12px,在chrome53,ff49和safari9中是15px,在ie11中是17px(通过截图中的photoshop中的测量完成,并且由testing结果certificate是正确的)。

但是,在某些情况下,也许你的应用程序没有使用默认的垂直滚动条的宽度。

因此,给定这些概念的定义,垂直滚动条的宽度应该等于(在伪代码中):

  • 布局尺寸:offsetWidth – clientWidth – (borderLeftWidth + borderRightWidth)

  • 渲染尺寸:boundingClientRect.width – clientWidth – (borderLeftWidth + borderRightWidth)

请注意,如果您不明白布局与渲染,请阅读mdn文章。

另外,如果你有另一个浏览器(或者你想自己查看testing结果),你可以在这里看到我的testing页面: http : //codepen.io/lingtalfi/pen/BLdBdL

我创build了一个更全面和更清晰的版本,有些人可能会发现有用的记住哪个名称对应于哪个值。 我使用了Chrome开发工具的颜色代码,并且对称地组织标签以更快地提取类比:

在这里输入图像说明

  • 注1:如果文本的方向被设置为从右到左(因为在这种情况下向左显示clientLeft还包括垂直滚动条的宽度,

  • 注2:最外面的线代表最近的定位父亲( position属性设置为不同于staticinitial值的元素)。 因此,如果直接容器不是定位元素,则该行不代表层次结构中的第一个容器,而代表层次中较高的另一个元素。 如果找不到定位的父对象,浏览器将把htmlbody元素作为引用


希望有人发现它有用,只是我2美分;)