【问题标题】:How do I retrieve an HTML element's actual width and height?如何检索 HTML 元素的实际宽度和高度?
【发布时间】:2010-09-22 14:18:03
【问题描述】:

假设我有一个<div>,我希望在浏览器的显示(视口)中居中。为此,我需要计算<div> 元素的宽度和高度。

我应该使用什么?请提供有关浏览器兼容性的信息。

【问题讨论】:

  • 请记住,通过任何方法获取元素的高度总是会产生性能影响,因为它会使浏览器重新计算所有元素的位置页面(重排)。因此,避免做太多。查看this list 了解哪些情况会触发回流。

标签: javascript html dhtml


【解决方案1】:

您应该使用.offsetWidth.offsetHeight 属性。 请注意,它们属于元素,而不是 .style

var width = document.getElementById('foo').offsetWidth;

Function .getBoundingClientRect() 在执行 CSS 转换后将元素的尺寸和位置返回为浮点数。

> console.log(document.getElementById('id').getBoundingClientRect())
DOMRect {
    bottom: 177,
    height: 54.7,
    left: 278.5,​
    right: 909.5,
    top: 122.3,
    width: 631,
    x: 278.5,
    y: 122.3,
}

【讨论】:

  • 当心!如果您最近对元素进行了某些 DOM 修改,则 offsetHeight/offsetWidth 可以返回 0。修改元素后,您可能必须在 setTimeout 调用中调用此代码。
  • 什么情况下返回0?
  • 我无法确定 offsetWidth 在我的情况下返回 0 的原因,因为我最初没有编写代码,但在 onload 事件中我总是得到 0。跨度>
  • @JDandChips:如果元素是 display:noneoffsetWidth 将为 0,而在这种情况下,计算出的 width 可能仍为正值。 visibility:hidden 不影响offsetWidth
  • @Supuhstar 都有不同的含义。 offsetWidth 返回“整个”框,包括内容、填充和边框;而clientWidth 仅返回内容框的大小(因此,只要元素具有任何非零填充和/或边框,它将具有较小的值)。 (为清晰起见,修改了模组)
【解决方案2】:

看看Element.getBoundingClientRect()

此方法将返回一个包含widthheight 和其他一些有用值的对象:

{
    width: 960,
    height: 71,
    top: 603,
    bottom: 674,
    left: 360,
    right: 1320
}

例如:

var element = document.getElementById('foo');
var positionInfo = element.getBoundingClientRect();
var height = positionInfo.height;
var width = positionInfo.width;

我相信这不存在.offsetWidth.offsetHeight 有时会返回0 的问题(如comments here 中所述)

另一个区别是getBoundingClientRect() 可能返回小数像素,其中.offsetWidth.offsetHeight 将四舍五入到最接近的整数。

IE8 注意getBoundingClientRect 不返回 IE8 及以下版本的高度和宽度。*

如果您必须支持 IE8,请使用 .offsetWidth.offsetHeight

var height = element.offsetHeight;
var width = element.offsetWidth;

值得注意的是,这个方法返回的Object并不是真正的普通对象。它的属性不是enumerable(例如,Object.keys 不能开箱即用。)

更多信息在这里: How best to convert a ClientRect / DomRect into a plain Object

参考:

【讨论】:

  • getboundingClientRect() 将返回通过 css 缩放的元素的实际宽度和高度,而 offsetHeightoffsetWidth 不会。
【解决方案3】:

注意这个答案写于 2008 年。当时对大多数人来说最好的跨浏览器解决方案确实是使用 jQuery。我将答案留给后代,如果您使用的是 jQuery,这是一个很好的方法。如果您使用的是其他框架或纯 JavaScript,则可接受的答案可能是要走的路。

从 jQuery 1.2.6 开始,您可以使用核心 CSS functionsheightwidth(或 outerHeightouterWidth,视情况而定)之一。

var height = $("#myDiv").height();
var width = $("#myDiv").width();

var docHeight = $(document).height();
var docWidth = $(document).width();

【讨论】:

    【解决方案4】:

    以防万一它对任何人有用,我将一个文本框、按钮和 div 都使用相同的 css:

    width:200px;
    height:20px;
    border:solid 1px #000;
    padding:2px;
    
    <input id="t" type="text" />
    <input id="b" type="button" />
    <div   id="d"></div>
    

    我在 chrome、firefox 和 ie-edge 中尝试过,我尝试使用 jquery 和不使用,我尝试使用和不使用 box-sizing:border-box。始终与&lt;!DOCTYPE html&gt;

    结果:

                                                                   Firefox       Chrome        IE-Edge    
                                                                  with   w/o    with   w/o    with   w/o     box-sizing
    
    $("#t").width()                                               194    200    194    200    194    200
    $("#b").width()                                               194    194    194    194    194    194
    $("#d").width()                                               194    200    194    200    194    200
    
    $("#t").outerWidth()                                          200    206    200    206    200    206
    $("#b").outerWidth()                                          200    200    200    200    200    200
    $("#d").outerWidth()                                          200    206    200    206    200    206
    
    $("#t").innerWidth()                                          198    204    198    204    198    204
    $("#b").innerWidth()                                          198    198    198    198    198    198
    $("#d").innerWidth()                                          198    204    198    204    198    204
    
    $("#t").css('width')                                          200px  200px  200px  200px  200px  200px
    $("#b").css('width')                                          200px  200px  200px  200px  200px  200px
    $("#d").css('width')                                          200px  200px  200px  200px  200px  200px
    
    $("#t").css('border-left-width')                              1px    1px    1px    1px    1px    1px
    $("#b").css('border-left-width')                              1px    1px    1px    1px    1px    1px
    $("#d").css('border-left-width')                              1px    1px    1px    1px    1px    1px
    
    $("#t").css('padding-left')                                   2px    2px    2px    2px    2px    2px
    $("#b").css('padding-left')                                   2px    2px    2px    2px    2px    2px
    $("#d").css('padding-left')                                   2px    2px    2px    2px    2px    2px
    
    document.getElementById("t").getBoundingClientRect().width    200    206    200    206    200    206
    document.getElementById("b").getBoundingClientRect().width    200    200    200    200    200    200
    document.getElementById("d").getBoundingClientRect().width    200    206    200    206    200    206
    
    document.getElementById("t").offsetWidth                      200    206    200    206    200    206
    document.getElementById("b").offsetWidth                      200    200    200    200    200    200
    document.getElementById("d").offsetWidth                      200    206    200    206    200    206
    

    【讨论】:

    • 只是要明确一点......这些浏览器中的任何一个做的事情都不同吗?我找不到任何差异...此外,我还没有拒绝投票,但这并没有真正直接回答问题,尽管可以很容易地对其进行编辑。
    • 不是为了回答这个问题——它已经被回答了。只是一些有用的信息,是的,所有主要的最新版本浏览器都同意这些值 - 这是一件好事。
    • 好吧...如果您的意图是回答这个问题,那么这并不真正属于这里(作为“答案”)。我会考虑将其放入一些外部资源(可能是 GitHub 要点或博客文章)中,并将其链接到对原始问题或答案之一的评论中。
    • @ZachLysobey 每条规则都有例外 - 这是一个很酷、很有用的东西。
    【解决方案5】:

    根据MDN: Determining the dimensions of elements

    offsetWidthoffsetHeight 返回“一个元素占用的空间总量,包括可见内容的宽度、滚动条(如果有)、内边距和边框”

    clientWidthclientHeight 返回“实际显示的内容占用了多少空间,包括填充但不包括边框、边距或滚动条”

    scrollWidthscrollHeight 返回“内容的实际大小,无论当前可见多少”

    所以这取决于测量的内容是否预计会超出当前的可视区域。

    【讨论】:

    【解决方案6】:

    您只需要为 IE7 和更早版本计算它(并且仅当您的内容没有固定大小时)。我建议使用 HTML 条件 cmets 来限制对不支持 CSS2 的旧 IE 的攻击。对于所有其他浏览器,请使用:

    <style type="text/css">
        html,body {display:table; height:100%;width:100%;margin:0;padding:0;}
        body {display:table-cell; vertical-align:middle;}
        div {display:table; margin:0 auto; background:red;}
    </style>
    <body><div>test<br>test</div></body>
    

    这是完美的解决方案。它以任意大小的&lt;div&gt; 为中心,并将其收缩包装到其内容的大小。

    【讨论】:

      【解决方案7】:

      修改元素样式很容易,但读取值有点棘手。

      除非您使用 javascript 中的内置方法调用 getComputedStyle,否则 JavaScript 无法读取来自 css(internal/external) 的任何元素样式属性 (elem.style)。

      getComputedStyle(element[, pseudo])

      元素:要为其读取值的元素。
      伪:如果需要,可以使用伪元素,例如 ::before。空字符串或无参数表示元素本身。

      结果是一个具有样式属性的对象,例如 elem.style,但现在涉及所有 css 类。

      例如,这里的样式看不到边距:

      <head>
        <style> body { color: red; margin: 5px } </style>
      </head>
      <body>
      
        <script>
          let computedStyle = getComputedStyle(document.body);
      
          // now we can read the margin and the color from it
      
          alert( computedStyle.marginTop ); // 5px
          alert( computedStyle.color ); // rgb(255, 0, 0)
        </script>
      
      </body>
      

      因此修改了您的 javaScript 代码以包含您希望获取其宽度/高度或其他属性的元素的 getComputedStyle

      window.onload = function() {
      
          var test = document.getElementById("test");
          test.addEventListener("click", select);
      
      
          function select(e) {                                  
              var elementID = e.target.id;
              var element = document.getElementById(elementID);
              let computedStyle = getComputedStyle(element);
              var width = computedStyle.width;
              console.log(element);
              console.log(width);
          }
      
      }
      

      计算和解析值

      CSS中有两个概念:

      计算的样式值是所有 CSS 规则和 CSS 之后的值 作为 CSS 级联的结果,应用了继承。它可以看起来 比如 height:1em 或 font-size:125%。

      已解析的样式值是最终应用于元素的样式值。 像 1em 或 125% 这样的值是相对的。浏览器接受计算 值并使所有单位固定和绝对,例如: 高度:20 像素或字体大小:16 像素。对于几何属性解析值 可能有一个浮点数,比如 width:50.5px。

      很久以前 getComputedStyle 被创建用于获取计算值,但结果证明解析值更方便,并且标准改变了。
      所以现在 getComputedStyle 实际上返回了属性的解析值。

      请注意:

      getComputedStyle 需要完整的属性名称

      您应该始终询问您想要的确切属性,例如 paddingLeft 或高度或宽度。否则正确 不保证结果。

      例如,如果有属性 paddingLeft/paddingTop,那么 getComputedStyle(elem).padding 我们应该得到什么?什么都没有,或者 也许是已知填充的“生成”值?没有标准 规则在这里。

      还有其他不一致之处。例如,某些浏览器 (Chrome) 在下面的文档中显示 10 像素,而其中一些 (Firefox) 则不会:

      <style>
        body {
          margin: 30px;
          height: 900px;
        }
      </style>
      <script>
        let style = getComputedStyle(document.body);
        alert(style.margin); // empty string in Firefox
      </script>
      

      更多信息https://javascript.info/styles-and-classes

      【讨论】:

        【解决方案8】:

        element.offsetWidth 和 element.offsetHeight 应该这样做,如上一篇文章中所建议的那样。

        但是,如果您只想使内容居中,则有更好的方法。假设您使用 xhtml 严格的 DOCTYPE。将 margin:0,auto 属性和所需宽度(以 px 为单位)设置为 body 标签。内容与页面居中对齐。

        【讨论】:

        • 我认为他也想垂直居中,这对 CSS 来说是一个正确的痛苦,除非你能满足一些特定的标准(例如已知大小的内容)
        【解决方案9】:

        ...似乎 CSS 有助于将 div 放在中心...

        <style>
         .monitor {
         position:fixed;/* ... absolute possible if on :root */
         top:0;bottom:0;right:0;left:0;
         visibility:hidden;
         }
         .wrapper {
         width:200px;/* this is size range */
         height:100px;
         position:absolute;
         left:50%;top:50%;
         visibility:hidden;
         }
        
         .content {
         position:absolute;
         width: 100%;height:100%;
         left:-50%;top:-50%;
         visibility:visible;
         }
        
        </style>
        
         <div class="monitor">
          <div class="wrapper">
           <div class="content">
        
         ... so you hav div 200px*100px on center ...
        
          </div>
         </div>
        </div>
        

        【讨论】:

          【解决方案10】:

          您也可以使用此代码:

          var divID = document.getElementById("divid");
          
          var h = divID.style.pixelHeight;
          

          【讨论】:

          • 嗯,在 Chrome 和 IE9 中有效,在 Firefox 中似乎无效。它仅适用于某些文档类型吗?
          • pixelHeight 是 Internet Explorer 的一项发明,不应再使用 stackoverflow.com/q/17405066/2194590
          【解决方案11】:

          弹性

          如果您想在屏幕中心的&lt;div&gt; 中显示某种弹出消息 - 那么您不需要阅读&lt;div&gt; 的大小,但您可以使用flex

          .box {
            width: 50px;
            height: 20px;
            background: red;
          }
          
          .container {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            width: 100vw;
            position: fixed; /* remove this in case there is no content under div (and remember to set body margins to 0)*/
          }
          <div class="container">
            <div class="box">My div</div>
          </div>

          【讨论】:

            【解决方案12】:

            我为此创建了一个实用函数,具有很高的灵活性:

            export type Size = {width: number, height: number};
            export enum GetSize_Method {
                /** Includes: content, padding. Excludes: border, margin, scroll-bar (if it has one), "position:absolute" descendants. */
                ClientSize = "ClientSize",
                /** Includes: content, padding, border, margin, scroll-bar (if it has one). Excludes: "position:absolute" descendants. */
                OffsetSize = "OffsetSize",
                /** Includes: content, padding, border, margin, scroll-bar (if it has one), "position:absolute" descendants. Excludes: none. */
                ScrollSize = "ScrollSize",
                /** Same as ScrollSize, except that it's calculated after the element's css transforms are applied. */
                BoundingClientRect = "BoundingClientRect",
                /** Lets you specify the exact list of components you want to include in the size calculation. */
                Custom = "Custom",
            }
            export type SizeComp = "content" | "padding" | "border" | "margin" | "scrollBar" | "posAbsDescendants";
            
            export function GetSize(el: HTMLElement, method = GetSize_Method.ClientSize, custom_sizeComps?: SizeComp[]) {
                let size: Size;
                if (method == GetSize_Method.ClientSize) {
                    size = {width: el.clientWidth, height: el.clientHeight};
                } else if (method == GetSize_Method.OffsetSize) {
                    size = {width: el.offsetWidth, height: el.offsetHeight};
                } else if (method == GetSize_Method.ScrollSize) {
                    size = {width: el.scrollWidth, height: el.scrollHeight};
                } else if (method == GetSize_Method.BoundingClientRect) {
                    const rect = el.getBoundingClientRect();
                    size = {width: rect.width, height: rect.height};
                } else if (method == GetSize_Method.Custom) {
                    const style = window.getComputedStyle(el, null);
                    const styleProp = (name: string)=>parseFloat(style.getPropertyValue(name));
            
                    const padding = {w: styleProp("padding-left") + styleProp("padding-right"), h: styleProp("padding-top") + styleProp("padding-bottom")};
                    const base = {w: el.clientWidth - padding.w, h: el.clientHeight - padding.h};
                    const border = {w: styleProp("border-left") + styleProp("border-right"), h: styleProp("border-top") + styleProp("border-bottom")};
                    const margin = {w: styleProp("margin-left") + styleProp("margin-right"), h: styleProp("margin-top") + styleProp("margin-bottom")};
                    const scrollBar = {w: (el.offsetWidth - el.clientWidth) - border.w - margin.w, h: (el.offsetHeight - el.clientHeight) - border.h - margin.h};
                    const posAbsDescendants = {w: el.scrollWidth - el.offsetWidth, h: el.scrollHeight - el.offsetHeight};
            
                    const sc = (name: SizeComp, valIfEnabled: number)=>custom_sizeComps.includes(name) ? valIfEnabled : 0;
                    size = {
                        width: sc("content", base.w) + sc("padding", padding.w) + sc("border", border.w)
                                + sc("margin", margin.w) + sc("scrollBar", scrollBar.w) + sc("posAbsDescendants", posAbsDescendants.w),
                        height: sc("content", base.h) + sc("padding", padding.h) + sc("border", border.h)
                                + sc("margin", margin.h) + sc("scrollBar", scrollBar.h) + sc("posAbsDescendants", posAbsDescendants.h),
                    };
                }
                return size;
            }
            

            用法:

            const el = document.querySelector(".my-element");
            console.log("Size:", GetSize(el, "ClientSize"));
            console.log("Size:", GetSize(el, "Custom", ["content", "padding", "border"]));
            

            【讨论】:

              【解决方案13】:

              使用宽度参数如下:

                 style={{
                    width: "80%",
                    paddingLeft: 100,
                    paddingRight: 200,
                    paddingTop: 30,
                    paddingBottom: 30,
                    border: "3px solid lightGray",
                  }}
              

              【讨论】:

              • 看起来像是 setting 宽度的 JSX 属性?
              【解决方案14】:

              如果 offsetWidth 返回 0,则可以获取元素的样式宽度属性并搜索一个数字。 "100px" -> 100

              /\d*/.exec(MyElement.style.width)

              【讨论】:

                【解决方案15】:

                这是 WKWebView 的代码,它决定了特定 Dom 元素的高度(不适用于整个页面)

                let html = "<body><span id=\"spanEl\" style=\"font-family: '\(taskFont.fontName)'; font-size: \(taskFont.pointSize - 4.0)pt; color: rgb(\(red), \(blue), \(green))\">\(textValue)</span></body>"
                webView.navigationDelegate = self
                webView.loadHTMLString(taskHTML, baseURL: nil)
                
                func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
                    webView.evaluateJavaScript("document.getElementById(\"spanEl\").getBoundingClientRect().height;") { [weak self] (response, error) in
                        if let nValue = response as? NSNumber {
                
                        }
                    }
                }
                

                【讨论】:

                • 澄清一下,这是 iOS swift 代码,对吧?不是 JavaScript。我拒绝投反对票(b/c 这实际上可能非常有用),但请注意,这确实回答了这个问题,并且可能更适合另一个特定于 iOS 的问题。如果不存在,或许可以考虑问一个并自行回答。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-08-13
                • 2014-04-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多