JavaScript如何获取dom元素的各种宽度高度?方案对比
发布于 作者:苏南大叔 来源:程序如此灵动~如果对页面元素的宽度高度做过仔细的调查,就可以发现:这些网页元素的尺寸的宽度width
和高度height
,有着很多的版本。如果较真的话,这些不同取值的宽度高度就显得很混乱。包括:width
/clientWidth
/offsetWidth
/scrollWidth
/innerWidth
/outerWidth
等。这些令人眼花缭乱的宽度之间究竟有什么样的区别和联系呢?
大家好,这里是苏南大叔的程序如此灵动博客,记录苏南大叔和计算机代码的故事。本文探讨使用js
获取页面元素宽度和高度的各种不同属性或方法。测试环境:谷歌浏览器@111.0.5563.111。
测试样本
本文的例子中使用了两个盒子元素作为例子。页面模式是标准模式<!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
)的实际宽度高度是固定不变的,padding
、border
还有滚动条都出现在代码定义的尺寸内部。 - 正常的盒子模型(
content-box
)的实际宽度高度比代码中定义的要大,因为padding
、border
还有滚动条都出现在代码定义的尺寸外部。
本文的测试样本,改编自下面的这两篇文章:
基础尺寸概念
一般来说,获取元素obj
的宽度,大家会使用obj.style.width
来获取。实际上这个值是最错误的值,因为它是必须定义在<dom style='width:300px'>
中才能获取到的,即使能够顺利获取,也大概率和实际的运行值不匹配,这里仅仅是获取定义的值。没通过元素的style
属性定义的话,获取的值为空。
那么实际的运行值和定义值之间的差值来自于padding
、border-width
、margin
以及滚动条。所以,先运算获取padding
、border
、margin
等基础值。
方法 | t1(怪异盒子) | t2(标准盒子) |
---|---|---|
-.style.width | 300px | 空 |
-.style.padding | 空 | 空 |
-.style.border | 空 | 空 |
-.style.margin | 空 | 空 |
getComputedStyle(document.querySelector('#-'), null).width | 360px | 360px |
getComputedStyle(document.querySelector('#-'), null).padding | 15px | 15px |
getComputedStyle(document.querySelector('#-'), null).borderWidth | 5px | 5px |
getComputedStyle(document.querySelector('#-'), null).margin | 10px | 10px |
目前这些width
、padding
、margin
、border
等因素取值完全相同,但是【测试的值和表现出来的效果却完全不同】。getComputedStyle
计算实际值的办法,来自于下面这篇文章:
clientWidth
和clientHeight
方法 | t1(怪异盒子) | t2(标准盒子) |
---|---|---|
-.clientWidth | 333 | 390 |
-.clientHeight | 50 | 90 |
元素可见区域的宽度,包括padding
,不包括滚动条和边框线,不包括margin
。指的是图中的蓝色部分,不包括灰框和滚动条。
offsetWidth
和offsetHeight
方法 | t1(怪异盒子) | t2(标准盒子) |
---|---|---|
-.offsetWidth | 360 | 400 |
-.offsetHeight | 60 | 100 |
offset
= 元素可见区域client
+ 边线和滚动条,不包括margin
。
scrollWidth
和scrollHeight
方法 | t1(怪异盒子) | t2(标准盒子) |
---|---|---|
-.scrollWidth | 333 | 390 |
-.scrollHeight | 90 | 90 |
scroll
包括可见部分client
以及不可见部分。不包括border
,不包括滚动条,不包括margin
,包括因为overflow
被隐藏的部分。
getComputedStyle().width
和jq.width()
方法 | t1(怪异盒子) | t2(标准盒子) |
---|---|---|
-.style.width | 300px | 空 |
-.style.height | 空 | 120px |
getComputedStyle(document.querySelector('#-'), null).width | 360px | 360px |
getComputedStyle(document.querySelector('#-'), null).height | 90px | 90px |
$('#-').width() | 320px | 360px |
$('#-').height() | 20px | 60px |
.style.
这个测量不准,仅仅是定义的值,和实际的值有差距。getComputedStyle
,不同的盒子模型虽然取值一致,但是效果差别很大。怪异盒子的尺寸,包括padding
和border
,是肉眼可见的宽度。标准盒子的尺寸,连padding
都不包括,是个需要想象才能想出来的尺寸,类似css
中inline
的感觉。- 基于
jq
的.width()计算的是最核心(inline
)的尺寸,无论盒子模型是啥,不包括padding
/border
/margin
。
jq.innerWidth()
和jq.outerWidth()
方法 | t1(怪异盒子) | t2(标准盒子) |
---|---|---|
$('#-').innerWidth() | 350 | 390 |
$('#-').outerWidth() | 360 | 400 |
$('#-').innerHeight() | 50 | 90 |
$('#-').outerHeight() | 60 | 100 |
- innerWidth() = width() + padding
- outerWidth() = width() + padding + border
方法 | t1(怪异盒子) | t2(标准盒子) |
---|---|---|
$('#-').innerWidth(true) | [object Object] | [object Object] |
$('#-').outerWidth(true) | 380 | 420 |
$('#-').innerHeight(true) | [object Object] | [object Object] |
$('#-').outerHeight(true) | 80 | 120 |
- innerWidth(true),非预期值,忽略。
- outerWidth(true) = width() + padding + border + margin = outerWidth() + margin
测试代码2
上述一系列结果的得出,使用了下面的测试代码。
<!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>
代码方案里面,使用了new Function()
的方式,通过字符串定义了函数体。参考文章:
相关文章
- https://newsn.net/say/js-get-computed-style.html
- https://newsn.net/say/css-important.html
- https://newsn.net/say/font-family-computed.html
- https://newsn.net/say/font-family-render.html
总结
更多js
和网页元素的交互文章,请参考链接:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。