【问题标题】:Understanding offsetWidth, clientWidth, scrollWidth and -Height, respectively分别了解offsetWidth、clientWidth、scrollWidth和-Height
【发布时间】:2014-01-30 14:15:23
【问题描述】:

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

此外,网络上有几个来源提供了令人困惑或不正确的信息。

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

【问题讨论】:

    标签: html css dom


    【解决方案1】:

    CSS 框模型相当复杂,尤其是在滚动内容方面。虽然浏览器使用 CSS 中的值来绘制框,但如果您只有 CSS,则使用 JS 确定所有尺寸并不简单。

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

    让我们详细介绍一下:

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

    试试看:jsFiddle


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

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

    很遗憾,我们可能会遇到舍入错误,因为 offsetWidthclientWidth 始终是整数,而实际大小可能是小数,缩放级别不是 1。

    注意这个

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

    在 Chrome 中是否可靠工作,因为 Chrome 返回 width 并已减去滚动条。 (另外,Chrome 会将 paddingBottom 渲染到滚动内容的底部,而其他浏览器则不会)

    【讨论】:

    • 对于那些寻求比整数更细粒度的人,请使用element.getBoundingClientRect()(请参阅developer.mozilla.org/en-US/docs/Web/API/Element.clientWidth 的注释)
    • 请注意,根据您的布局,scrollWidth 和 scrollHeight 对于获取伪元素 ::before 和 ::after 的大小非常有用。
    • 为什么scrollHeight 包含padding-bottomscrollWidth 不包含padding-right
    • clientWidth for document.documentElement.clientWidth 不同,因为它似乎包括 paddingbordersmargin
    • 根据 clientWidth 规范,如果元素是 HTMLbody 元素“返回视口宽度,不包括渲染滚动条的大小(如果有)。”,所以 document.documentElement.clientWidth包括填充/边框/边距w3.org/TR/cssom-view/#dom-element-clientwidth
    【解决方案2】:

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

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

    • 注2:最外层的线代表最近的定位父 (一个元素,其position 属性设置为不同于 staticinitial)。因此,如果直接容器不是定位 元素,则该行不代表第一个容器 层次结构,但层次结构中更高的另一个元素。如果不 定位 找到父级,浏览器将采用htmlbody 元素作为参考


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

    【讨论】:

    • 这张图很干净,但是为什么要省略填充呢?
    • @Magnus 它使用了 Chrome Dev Tool 的颜色代码:灰蓝色表示内容,灰绿色表示填充,深米色表示边框,浅橙色表示边距。
    • 我不确定这是否正确...如果没有颜色区域的标签,很难分辨。您似乎在说 clientWidth 不包括填充...这是错误的
    • @DonP 如上所述,它遵循 Chrome 开发工具的颜色约定(较低的不透明度区域表示浏览器中的隐藏区域)。这是一个交互式版本,用于阐明 clientWidth 值:codepen.io/lual/pen/oNeydMz。浏览器确实会考虑填充,但如果元素的宽度设置为特定值并且 box-sizing 设置为border-box,则不会影响最终值。将来我可能会创建一个更好的静态图形版本,但事实上,有些细节还不够清晰。
    【解决方案3】:

    如果你想使用 scrollWidth 来获得 "REAL" CONTENT WIDTH/HEIGHT(因为内容可以比 css 定义的宽度/高度框更大) scrollWidth/Height 非常不可靠,因为如果内容太大,某些浏览器似乎会“移动”paddingRIGHT 和 paddingBOTTOM。然后他们将填充放在“内容太宽/高”的右侧/底部(见下图)。

    ==>因此,要在某些浏览器中获得 REAL CONTENT WIDTH,您必须从滚动宽度中减去两个填充,而在某些浏览器中,您只需减去 LEFT Padding。

    我找到了解决方案并想将其添加为评论,但不允许。所以我拍了这张照片,并在“移动的填充”和“不可靠的滚动宽度”方面更加清晰。 在蓝色区域中,您可以找到我关于如何获得“真实”内容宽度的解决方案!

    希望这有助于让事情变得更加清晰!

    【讨论】:

    • 大声笑。 . . . . . .
    【解决方案4】:

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

    它还解释了 boundingClientRect 的宽度/高度与 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)

      • 滚动宽度:508 (edge13)
      • scrollWidth: 503 (ie11)
      • scrollHeight: 916 (chrome53, safari9)
      • 滚动高度: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)

      • 滚动宽度:478 (edge13)
      • scrollWidth: 473 (ie11)
      • scrollHeight: 916 (chrome53, safari9)
      • 滚动高度: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)

      • 滚动宽度:508 (edge13)
      • scrollWidth: 503 (ie11)
      • scrollHeight: 916 (chrome53, safari9)
      • 滚动高度: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 中测量完成,并通过测试结果证明正确)。

    但是,在某些情况下,您的应用可能没有使用默认的垂直滚动条宽度。

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

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

    • 渲染维度:boundingClientRect.width - clientWidth - (borderLeftWidth + borderRightWidth)

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

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

    【讨论】:

      【解决方案5】:

      我的个人备忘单,涵盖:

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

      使用小型/简单/非一体式图表 :)


      ? 查看原图:https://docs.google.com/drawings/d/1bOOJnkN5G_lBs3Oz9NfQQH1I0aCrX5EZYPY3mu3_ROI/edit?usp=sharing

      【讨论】:

        【解决方案6】:

        客户端宽度/高度偏移宽度/高度计算 - 快速总结使用示例 css 样式

        参考:https://javascript.info/size-and-scroll

        【讨论】:

          猜你喜欢
          • 2021-01-26
          • 2015-01-09
          • 1970-01-01
          • 2015-08-03
          • 2020-06-02
          • 2017-06-19
          • 2014-12-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多