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

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

此外,网络上也有一些来源提供令人困惑或不正确的信息。

你能给我一个完整的解释,包括一些视觉提示吗? 此外,如何使用这些值来计算滚动条宽度?< / p >
218184 次浏览

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返回width,滚动条已经被减去。(此外,Chrome渲染paddingBottom滚动内容的底部,而其他浏览器没有)

如果你想使用scrollWidth来获取“真正的” 内容宽/高(因为内容可以比css定义的width/height-Box更大),scrollWidth/Height非常不可靠就像一些浏览器似乎“移动”paddingRIGHT &如果内容太大,则填充底部。然后,他们将填充放置在“太宽/高内容”的右侧/底部(见下图)。

因此,在某些浏览器中,要获得REAL CONTENT WIDTH,你必须从scrollwidth中减去两个填充,而在某些浏览器中,你只需要减去LEFT填充。

我为此找到了一个解决方案,并想将其作为评论添加,但不被允许。所以我拍了这张照片,让它在“移动填充”和“不可靠的scrollWidth”方面更清楚一些。在蓝色区域,你可以找到我的解决方案,如何获得“真正的”内容宽度!

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

enter image description here

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

它还解释了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);
}

结果如下:

  • < p > div1

    • offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
    • offsetHeight: 330 (chrome53, ff49, safari9, edge13, ie11)
    • bcr。宽度:530 (chrome53, ff49, safari9, edge13, ie11)
    • bcr。高度: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)
    • 李< / ul > < / >
    • < p > div2

      • offsetWidth: 500 (chrome53, ff49, safari9, edge13, ie11)
      • offsetHeight: 300 (chrome53, ff49, safari9, edge13, ie11)
      • bcr。宽度:500 (chrome53, ff49, safari9, edge13, ie11)
      • bcr。身高: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)
      • 李< / ul > < / >
      • < p > div3

        • offsetWidth: 530 (chrome53, ff49, safari9, edge13, ie11)
        • offsetHeight: 330 (chrome53, ff49, safari9, edge13, ie11)
        • bcr。宽度:265 (chrome53, ff49, safari9, edge13, ie11)
        • bcr。高度: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)
        • 李< / ul > < / >

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

        下面是我对这些概念的定义:

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

        注意:默认的垂直滚动条宽度在edge13中是12px,在chrome53, ff49和safari9中是15px,在ie11中是17px(在photoshop中从截图测量,并被测试结果证明是正确的)。

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

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

        • 布局尺寸:offsetWidth - clientWidth - (borderLeftWidth + borderrighttwidth)

        • 渲染维度:boundingClientRect。width - clientWidth - (borderLeftWidth + borderrighttwidth)

        注意,如果你不理解布局和渲染,请阅读mdn文章。

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

我创建了一个更全面和更清晰的版本,有些人可能会发现它有助于记住哪个名称对应哪个值。我使用Chrome Dev Tool的颜色代码和标签是对称组织的,以更快地拾取类比:

enter image description here

    注1:clientLeft还包括垂直滚动的宽度 条,如果文本的方向设置为从右向左(因为 Bar显示在左侧)

  • 注2:最外面的一行表示最接近的定位< em > < / em >父元素 (一个元素,其position属性被设置为不同于 staticinitial)。因此,如果直接容器不是定位< em > < / em > . c 元素,那么这一行就不代表其中的第一个容器 层次结构是层次结构中更高的另一个元素。如果没有 如果找到了定位< em > < / em >父节点,浏览器就会取htmlbody . c 元素作为引用


希望有人觉得它有用,只是我的2美分;)

我的个人小抄,包括:

DOM元素维度

  • .offsetWidth / .offsetHeight
  • .clientWidth / .clientHeight
  • .scrollWidth / .scrollHeight
  • .scrollLeft / .scrollTop
  • .getBoundingClientRect()

使用小的/简单的/非全合一的图表:)


👁见full-size: https://docs.google.com/drawings/d/1bOOJnkN5G_lBs3Oz9NfQQH1I0aCrX5EZYPY3mu3_ROI/edit?usp=sharing

客户端宽/高抵消宽/高计算- 快速总结使用样本css样式:

enter image description here

裁判:https://javascript.info/size-and-scroll