有许多 JavaScript 属性允许我们读取有关元素宽度、高度和其他几何特征的信息。
当在 JavaScript 中移动或定位元素时,我们经常需要它们。
示例元素
作为演示属性的示例元素,我们将使用下面给出的元素
<div id="example">
...Text...
</div>
<style>
#example {
width: 300px;
height: 200px;
border: 25px solid #E8C48F;
padding: 20px;
overflow: auto;
}
</style>
它有边框、填充和滚动。完整的特性集。没有边距,因为它们不是元素本身的一部分,也没有针对它们的特殊属性。
元素看起来像这样
您可以在沙盒中打开文档。
当元素有滚动条时,上图展示了最复杂的情况。一些浏览器(并非全部)通过从内容中获取空间(上面标记为“内容宽度”)来为其保留空间。
因此,如果没有滚动条,内容宽度将为 300px,但如果滚动条宽 16px(宽度可能因设备和浏览器而异),则只有 300 - 16 = 284px,我们应该考虑到这一点。这就是本章中的示例假设存在滚动条的原因。没有它,一些计算会更简单。
padding-bottom 区域可以用文本填充通常,填充在我们的插图中显示为空,但如果元素中有大量文本并且溢出,则浏览器会在 padding-bottom 中显示“溢出”文本,这是正常的。
几何
以下是具有几何属性的整体图片
从技术上讲,这些属性的值是数字,但这些数字是“像素”,因此这些是像素测量值。
让我们从元素外部开始探索这些属性。
offsetParent、offsetLeft/Top
这些属性很少需要,但它们仍然是“最外层”几何属性,所以我们从它们开始。
offsetParent 是浏览器在渲染期间用于计算坐标的最近祖先。
这是以下之一的最近祖先
- CSS 定位(
position为absolute、relative、fixed或sticky),或 <td>、<th>或<table>,或<body>.
属性 offsetLeft/offsetTop 提供相对于 offsetParent 左上角的 x/y 坐标。
在下面的示例中,内部 <div> 将 <main> 作为 offsetParent,并且 offsetLeft/offsetTop 从其左上角(180)偏移。
<main style="position: relative" id="main">
<article>
<div id="example" style="position: absolute; left: 180px; top: 180px">...</div>
</article>
</main>
<script>
alert(example.offsetParent.id); // main
alert(example.offsetLeft); // 180 (note: a number, not a string "180px")
alert(example.offsetTop); // 180
</script>
有几种情况 offsetParent 为 null
- 对于未显示的元素(
display:none或不在文档中)。 - 对于
<body>和<html>。 - 对于具有
position:fixed的元素。
offsetWidth/Height
现在让我们继续讨论元素本身。
这两个属性是最简单的属性。它们提供了元素的“外部”宽度/高度。或者,换句话说,它的完整大小,包括边框。
对于我们的示例元素
offsetWidth = 390- 外部宽度,可以计算为内部 CSS 宽度(300px)加上填充(2 * 20px)和边框(2 * 25px)。offsetHeight = 290- 外部高度。
几何属性仅针对显示的元素计算。
如果某个元素(或其任何祖先元素)具有 display:none 或不在文档中,则所有几何属性均为零(或 offsetParent 的 null)。
例如,当我们创建了一个元素但尚未将其插入文档中,或它(或其祖先元素)具有 display:none 时,offsetParent 为 null,offsetWidth、offsetHeight 为 0。
我们可以使用它来检查元素是否隐藏,如下所示
function isHidden(elem) {
return !elem.offsetWidth && !elem.offsetHeight;
}
请注意,对于屏幕上显示但大小为零的元素,此类 isHidden 会返回 true。
clientTop/Left
在元素内部,我们有边框。
要测量它们,有属性 clientTop 和 clientLeft。
在我们的示例中
clientLeft = 25– 左边框宽度clientTop = 25– 顶部边框宽度
…但要准确地说,这些属性不是边框宽度/高度,而是内部相对于外部的相对坐标。
有什么区别?
当文档从右到左(操作系统使用阿拉伯语或希伯来语)时,差异就显现出来了。此时滚动条不在右侧,而是在左侧,然后 clientLeft 也包括滚动条宽度。
在这种情况下,clientLeft 不是 25,而是滚动条宽度 25 + 16 = 41。
以下是希伯来语示例
clientWidth/Height
这些属性提供元素边框内区域的大小。
它们包括内容宽度和内边距,但不包括滚动条
在上面的图片中,我们首先考虑 clientHeight。
没有水平滚动条,因此它恰好是边框内内容的总和:CSS 高度 200px 加上顶部和底部内边距(2 * 20px),总计 240px。
现在是 clientWidth – 这里的内容宽度不是 300px,而是 284px,因为 16px 被滚动条占用。因此,总和是 284px 加上左右内边距,总计 324px。
如果没有内边距,则 clientWidth/Height 恰好是内容区域,位于边框和滚动条(如果存在)内部。
因此,当没有内边距时,我们可以使用 clientWidth/clientHeight 来获取内容区域大小。
scrollWidth/Height
这些属性类似于 clientWidth/clientHeight,但它们还包括滚动出去(隐藏)的部分
在上图中
scrollHeight = 723– 是内容区域的完整内部高度,包括滚动出去的部分。scrollWidth = 324– 是完整的内部宽度,此处没有水平滚动,因此它等于clientWidth。
我们可以使用这些属性将元素扩展到其完整的宽度/高度。
像这样
// expand the element to the full content height
element.style.height = `${element.scrollHeight}px`;
单击按钮以展开元素
scrollLeft/scrollTop
属性 scrollLeft/scrollTop 是元素隐藏的、滚动出去的部分的宽度/高度。
在下图中,我们可以看到带有垂直滚动的块的 scrollHeight 和 scrollTop。
换句话说,scrollTop 是“向上滚动多少”。
scrollLeft/scrollTop这里的几何属性大多数是只读的,但 scrollLeft/scrollTop 可以更改,浏览器将滚动元素。
如果你单击下面的元素,代码 elem.scrollTop += 10 将执行。这将使元素内容向下滚动 10px。
我
1
2
3
4
5
6
7
8
9
将 scrollTop 设置为 0 或大值(如 1e9)将分别使元素滚动到最顶部/底部。
不要从 CSS 中获取宽度/高度
我们刚刚介绍了 DOM 元素的几何属性,可用于获取宽度、高度和计算距离。
但正如我们在章节 样式和类 中所知,我们可以使用 getComputedStyle 读取 CSS 高度和宽度。
那么为什么不使用 getComputedStyle 来读取元素的宽度,如下所示呢?
let elem = document.body;
alert( getComputedStyle(elem).width ); // show CSS width for elem
为什么我们应该使用几何属性?原因有两个
-
首先,CSS
width/height取决于另一个属性:box-sizing,它定义了 CSS 宽度和高度的“是什么”。出于 CSS 目的而更改box-sizing可能会破坏此类 JavaScript。 -
其次,CSS
width/height可能为auto,例如对于内联元素<span id="elem">Hello!</span> <script> alert( getComputedStyle(elem).width ); // auto </script>从 CSS 的角度来看,
width:auto是完全正常的,但在 JavaScript 中,我们需要一个精确的px大小,以便在计算中使用。因此,这里的 CSS 宽度是无用的。
还有一个原因:滚动条。有时,在没有滚动条的情况下正常工作的代码会因滚动条而出现错误,因为在某些浏览器中,滚动条会占用内容的空间。因此,可用于内容的实际宽度小于 CSS 宽度。而 clientWidth/clientHeight 会考虑这一点。
…但使用 getComputedStyle(elem).width 的情况有所不同。一些浏览器(例如 Chrome)会返回实际的内部宽度(减去滚动条),而另一些浏览器(例如 Firefox)会返回 CSS 宽度(忽略滚动条)。这种跨浏览器的差异是不使用 getComputedStyle 的原因,而应依赖于几何属性。
如果你的浏览器为滚动条保留了空间(大多数 Windows 浏览器都会这样做),那么你可以在下面进行测试。
带有文本的元素具有 CSS width:300px。
在台式机 Windows 操作系统上,Firefox、Chrome 和 Edge 都为滚动条保留了空间。但 Firefox 显示 300px,而 Chrome 和 Edge 显示的更少。这是因为 Firefox 返回 CSS 宽度,而其他浏览器返回“实际”宽度。
请注意,所描述的差异仅与从 JavaScript 中读取 getComputedStyle(...).width 有关,在视觉上,一切都正确。
总结
元素具有以下几何属性
offsetParent– 是最近的定位祖先或td、th、table、body。offsetLeft/offsetTop– 相对于offsetParent的左上角的坐标。offsetWidth/offsetHeight– 元素的“外部”宽度/高度,包括边框。clientLeft/clientTop– 从左上角外角到左上角内角(内容 + 内边距)的距离。对于从左到右的操作系统,它们始终是左右边框的宽度。对于从右到左的操作系统,垂直滚动条位于左侧,因此clientLeft也包括其宽度。clientWidth/clientHeight– 内容的宽度/高度,包括填充,但不包括滚动条。scrollWidth/scrollHeight– 内容的宽度/高度,就像clientWidth/clientHeight,但还包括元素中已滚动出去不可见的部分。scrollLeft/scrollTop– 元素中已滚动出去的上半部分的宽度/高度,从其左上角开始。
除了 scrollLeft/scrollTop 之外,所有属性都是只读的,如果更改了 scrollLeft/scrollTop,浏览器将滚动该元素。
评论
<code>标签,对于多行 - 将其包装在<pre>标签中,对于 10 行以上 - 使用沙盒 (plnkr,jsbin,codepen...)