之前通过《clientX、pageX、offsetX 和 screenX》一文我介绍了关于如何去获取鼠标指针的当下坐标信息的知识。本文则是对几种获取页面元素宽高信息的 js 方法进行了归纳对比总结,希望能对需要的掘友们有所裨益。
前期准备
我先准备了 2 个用来测试的 div:
<div id="box1"></div>
<div id="box2"></div>
样式如下,红色的 box1 有使用 css 明确定义的宽高,绿色的 box2 则是只定义了高度,宽度为父元素(页面)的 50%:
body {
margin: 0;
}
#box1 {
width: 100px;
height: 100px;
background-color: brown;
}
#box2 {
width: 50%;
height: 100px;
background-color: cadetblue;
}
效果如下:
我通过 id 获取到了 box1 和 box2 对象:
const box1 = document.getElementById('box1')
const box2 = document.getElementById('box2')
offsetWidth 与 offsetHeight
首先介绍的是 HTMLElement 的只读属性 offsetWidth 与 offsetHeight。我们可以直接打印查看 box1 和 box2 的宽高:
window.addEventListener('resize', () => {
console.log(box1.offsetWidth, box1.offsetHeight)
console.log(box2.offsetWidth)
})
结果如下,当文档宽度为 642.5px 时,box1.offsetWidth 和 box1.offsetHeight 均为 100,box2.offsetWidth 的打印输出为 321:
表明:
offsetWidth或offsetHeight可以动态获取元素的宽高;- 获取的结果是不带单位的;
- 获取的结果如果为小数,会被取整。
getBoundingClientRect()
getBoundingClientRect() 是一个方法,使用方法如下:
const rect1 = box1.getBoundingClientRect()
返回的结果是一个 DOMRect 对象,其中除了元素的宽高信息外还有其它属性:
打印查看 box1 和 box2 的宽度:
window.addEventListener('resize', () => {
const rect1 = box1.getBoundingClientRect()
const rect2 = box2.getBoundingClientRect()
console.log(rect1.width)
console.log(rect2.width)
})
结果如下:
表明:
getBoundingClientRect()可以动态获取元素的宽度(高度亦然);- 获取的结果同
offsetWidth一样也是不带单位的; - 与
offsetWidth不同的是,它的结果不会取整。
getComputedStyle()
getComputedStyle() 也是一个方法,使用方式如下:
const style1 = getComputedStyle(box1)
打印查看 style1,结果如下:
返回的对象基本上包含了 box1 的所有 css 属性。我们只需要查看 width 属性,所以可以:
window.addEventListener('resize', () => {
const style1 = getComputedStyle(box1)
const style2 = getComputedStyle(box2)
console.log(style1.width)
console.log(style2.width)
})
得到的结果如下:
表明:
getComputedStyle()也可以动态地获取元素的宽度;- 获取的结果是带单位的,而且单位值都是绝对单位,比如原本是
rem会换算为px,这点与getBoundingClientRect()或offsetWidth不同; - 它的结果也不会取整。
边框、内边距的影响
现在我给 box1 的 css 添加上边框 (border) 和内边距 (padding),研究对几种获取宽高的方式是否会产生影响:
#box1 {
/* ...忽略之前的定义 */
border: 1px solid #333;
padding-left: 10px;
}
- offsetWidth 与 offsetHeight
现在打印的结果中,box1.offsetWidth 就会为 112,box1.offsetHeight 为 102:
这说明 offsetWidth 和 offsetHeight 的值是会包含边框和内边距的。
- getBoundingClientRect()
rect1.width 的打印结果会约等于 box1 的 width(100px) + border(1px*2) + padding(10px) 的 112px:
可见 getBoundingClientRect() 获取的宽高是会包含边框和内边距的。
- getComputedStyle()
即使添加了边框与内边距,打印 style1.width 得到的结果依旧为 100px:
可见获取的仅仅是 css 属性中的 width 的值,与其它无关。
盒模型的影响
如果我再将 box1 的盒模型做出修改,改为 border-box:
#box1 {
/* ...忽略之前的定义 */
box-sizing: border-box;
}
此时,无论是通过 offsetWidth 还是 getBoundingClientRect() 或是 getComputedStyle(),它们获取到的关于 box1 宽度的结果,都为 100(或 100px):
补充
与 offsetHeight(offsetWidth同理)相似,Element 上拥有只读属性 clientHeight 和 scrollHeight,它们也可以获取元素的高度,但其值都是包含内边距,而不包括边框。另外 scrollHeight 的值是包括由于 overflow 溢出而在屏幕上不可见的内容。
clientHeight
比如现有一个 div 如下:
<div id="box"></div>
样式如下
#box {
width: 100px;
height: 100px;
background-color: brown;
border: 5px solid #333;
padding: 10px;
box-sizing: border-box;
}
打印查看 clientHeight:
console.log(box.clientHeight)
值会为 90。即在 box-sizing 为 border-box 的情况下,由 height - border * 2 得到。
如果 box-sizing 为默认的 content-box,则打印的值会为 120,包含内边距,但不包括边框。
scrollHeight
如果现在直接打印查看 box 的 scrollHeight,那么值也会为 90。要看出与 clientHeight 的区别需要在 box 内部添加一个元素,让其高度超过 box 本身:
<div id="box">
<div style="height: 200px"></div>
</div>
然后给 box 添加样式 overflow: hidden;(或是 overflow: scroll;),此时打印查看 scrollHeight:
console.log(box.scrollHeight)
得到的值会是 220,即 box 内部的元素的实际高度 200 + box 的内边距 * 2,与 box-sizing 无关。
