有许多 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...)