我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

如果对页面元素的宽度高度做过仔细的调查,就可以发现:这些网页元素的尺寸的宽度width和高度height,有着很多的版本。如果较真的话,这些不同取值的宽度高度就显得很混乱。包括:width/clientWidth/offsetWidth/scrollWidth/innerWidth/outerWidth等。这些令人眼花缭乱的宽度之间究竟有什么样的区别和联系呢?

苏南大叔:JavaScript如何获取dom元素的各种宽度高度?方案对比 - 宽度高度对比
JavaScript如何获取dom元素的各种宽度高度?方案对比(图4-1)

大家好,这里是苏南大叔的程序如此灵动博客,记录苏南大叔和计算机代码的故事。本文探讨使用js获取页面元素宽度和高度的各种不同属性或方法。测试环境:谷歌浏览器@111.0.5563.111。

测试样本

本文的测试样本,改编自下面的这两篇文章:

苏南大叔:JavaScript如何获取dom元素的各种宽度高度?方案对比 - 测试样本
JavaScript如何获取dom元素的各种宽度高度?方案对比(图4-2)

本文的例子中使用了两个盒子元素作为例子。页面模式是标准模式<!DOCTYPE html>,盒子模型分别是怪异模式border-box和正常模式content-box

<div>盒子模型360*60</div>
<div id="t1" style="width:300px">t1,border-box</div>
<div id="t2" style="height:120px">t2,content-box</div>
<style>
  div {
    width: 360px !important;
    height: 60px !important;
    line-height: 60px;
    text-align: center;
    vertical-align: middle;
    margin: 10px;
    background-color: blue;
    color: #ffffff;
    clear: both;
    overflow:auto;
  }
  div#t1 {
    box-sizing: border-box;
    padding: 15px;
    border: 5px solid gray;
  }
  div#t2 {
    box-sizing: content-box;
    padding: 15px;
    border: 5px solid gray;
  }
</style>

从运行截图上可以看到:

  • 盒子模型的默认形态是content-box。对比的标准目标尺寸是360*60
  • 怪异盒子模型(border-box)的实际宽度高度是固定不变的,paddingborder还有滚动条都出现在代码定义的尺寸内部。
  • 正常的盒子模型(content-box)的实际宽度高度比代码中定义的要大,因为paddingborder还有滚动条都出现在代码定义的尺寸外部。

基础尺寸概念

一般来说,获取元素obj的宽度,大家会使用obj.style.width来获取。实际上这个值是最错误的值,因为它是必须定义在<dom style='width:300px'>中才能获取到的,即使能够顺利获取,也大概率和实际的运行值不匹配,这里仅仅是获取定义的值。没通过元素的style属性定义的话,获取的值为空。

那么实际的运行值和定义值之间的差值来自于paddingborder-widthmargin以及滚动条。所以,先运算获取paddingbordermargin等基础值。

方法t1(怪异盒子)t2(标准盒子)
-.style.width300px
-.style.padding
-.style.border
-.style.margin
getComputedStyle(document.querySelector('#-'), null).width360px360px
getComputedStyle(document.querySelector('#-'), null).padding15px15px
getComputedStyle(document.querySelector('#-'), null).borderWidth5px5px
getComputedStyle(document.querySelector('#-'), null).margin10px10px

目前这些widthpaddingmarginborder等因素取值完全相同,但是【测试的值和表现出来的效果却完全不同】。getComputedStyle计算实际值的办法,来自于下面这篇文章:

clientWidthclientHeight

方法t1(怪异盒子)t2(标准盒子)
-.clientWidth333390
-.clientHeight5090

元素可见区域的宽度,包括padding,不包括滚动条和边框线,不包括margin。指的是图中的蓝色部分,不包括灰框和滚动条。

offsetWidthoffsetHeight

方法t1(怪异盒子)t2(标准盒子)
-.offsetWidth360400
-.offsetHeight60100

offset = 元素可见区域client + 边线和滚动条,不包括margin

scrollWidthscrollHeight

方法t1(怪异盒子)t2(标准盒子)
-.scrollWidth333390
-.scrollHeight9090

scroll包括可见部分client以及不可见部分。不包括border,不包括滚动条,不包括margin,包括因为overflow被隐藏的部分。

getComputedStyle().widthjq.width()

方法t1(怪异盒子)t2(标准盒子)
-.style.width300px
-.style.height120px
getComputedStyle(document.querySelector('#-'), null).width360px360px
getComputedStyle(document.querySelector('#-'), null).height90px90px
$('#-').width()320px360px
$('#-').height()20px60px
  • .style.这个测量不准,仅仅是定义的值,和实际的值有差距。
  • getComputedStyle,不同的盒子模型虽然取值一致,但是效果差别很大。怪异盒子的尺寸,包括paddingborder,是肉眼可见的宽度。标准盒子的尺寸,连padding都不包括,是个需要想象才能想出来的尺寸,类似cssinline的感觉。
  • 基于jq的.width()计算的是最核心(inline)的尺寸,无论盒子模型是啥,不包括padding/border/margin

苏南大叔:JavaScript如何获取dom元素的各种宽度高度?方案对比 - jq的尺寸1
JavaScript如何获取dom元素的各种宽度高度?方案对比(图4-3)

苏南大叔:JavaScript如何获取dom元素的各种宽度高度?方案对比 - jq的尺寸2
JavaScript如何获取dom元素的各种宽度高度?方案对比(图4-4)

jq.innerWidth()jq.outerWidth()

方法t1(怪异盒子)t2(标准盒子)
$('#-').innerWidth()350390
$('#-').outerWidth()360400
$('#-').innerHeight()5090
$('#-').outerHeight()60100
  • innerWidth() = width() + padding
  • outerWidth() = width() + padding + border
方法t1(怪异盒子)t2(标准盒子)
$('#-').innerWidth(true)[object Object][object Object]
$('#-').outerWidth(true)380420
$('#-').innerHeight(true)[object Object][object Object]
$('#-').outerHeight(true)80120
  • innerWidth(true),非预期值,忽略。
  • outerWidth(true) = width() + padding + border + margin = outerWidth() + margin

本文测试代码

本文的测试代码,使用了new Function()的方式,通过字符串定义了函数体。参考文章:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>盒子模型360*60</div>
    <div id="t1" style="width: 300px">t1,border-box</div>
    <div id="t2" style="height: 120px">t2,content-box</div>
    <style>
      div {
        width: 360px !important;
        height: 60px !important;
        line-height: 60px;
        text-align: center;
        vertical-align: middle;
        margin: 10px;
        background-color: blue;
        color: #ffffff;
        clear: both;
        overflow: auto;
      }
      div#t1 {
        box-sizing: border-box;
        padding: 15px;
        border: 5px solid gray;
      }
      div#t2 {
        box-sizing: content-box;
        padding: 15px;
        border: 5px solid gray;
      }
    </style>
    <table>
      <tr>
        <th>方法</th>
        <th>t1</th>
        <th>t2</th>
      </tr>
    </table>
    <style>
      table {
        width: 100%;
        border-collapse: collapse;
        margin: 0 auto;
        text-align: center;
      }
      table td,
      table th {
        border: 1px solid #cad9ea;
        color: #666;
        height: 30px;
      }
      table th {
        background-color: #cce8eb;
        width: 100px;
      }
      table tr:nth-child(odd) {
        background: #fff;
      }
      table tr:nth-child(even) {
        background: #f5fafa;
      }
    </style>
    <script src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js"></script>
    <script>
      var tabObj = document.getElementsByTagName("table")[0]; //获取添加数据的表格
      var rowsNum = tabObj.rows.length;                       //获取当前行数
      // var colsNum = tabObj.rows[rowsNum - 1].cells.length;    //获取行的列数
      var infos = [
        "obj.style.width","obj.style.height",
        "obj.style.padding",
        "obj.style.border",
        "obj.style.margin",
        "getComputedStyle(document.querySelector('#obj'), null).width",
        "getComputedStyle(document.querySelector('#obj'), null).height",
        "getComputedStyle(document.querySelector('#obj'), null).padding",
        "getComputedStyle(document.querySelector('#obj'), null).borderWidth",
        "getComputedStyle(document.querySelector('#obj'), null).margin",
        "obj.clientWidth","obj.clientHeight",
        "obj.offsetWidth","obj.offsetHeight",
        "obj.scrollWidth","obj.scrollHeight",  // 边线(border+滚动条)
        "$('#obj').width()",                   // width()返回元素的宽高,不包括padding/border/margin
        "$('#obj').height()",
        "$('#obj').innerWidth()",              // innerWidth()返回元素的宽高 + padding
        "$('#obj').innerWidth(true)",
        "$('#obj').innerHeight()",
        "$('#obj').innerHeight(true)",
        "$('#obj').outerWidth()",              // outerWidth()返回元素的宽高 + padding + border
        "$('#obj').outerWidth(true)",          // outerWidth(true)返回元素宽高 + padding + border + margin
        "$('#obj').outerHeight()", 
        "$('#obj').outerHeight(true)",
      ];
      var objs = ["t1", "t2"];
      for (var j = 0; j < infos.length; j++) {
        var addRow = tabObj.insertRow(rowsNum);
        var addRow0 = addRow.insertCell(0);
        var js = infos[j].replace("obj", "-");
        addRow0.innerHTML = js;
        // console.log(js);
        for (var i = 0; i < objs.length; i++) {
          var addRow1 = addRow.insertCell(i + 1);
          var js2 = infos[j].replace("obj", objs[i]);
          addRow1.innerHTML = new Function("return " + js2)();
        }
        rowsNum++;
      }
    </script>
  </body>
</html>

相关文章

总结

更多js和网页元素的交互文章,请参考链接:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   js