使用 CSSOM 测量 DOM 元素
本文根据 W3C CSSOM view
formal, draft 与 MDN WEB DOCS
中一些测量元素的 CSSOM
属性归纳总结出一些常见基础的元素测量方案。
先决条件
Note that visibility: hidden is different from display: none. The former makes the element invisible, but the element still occupies space in the layout (that is, it's rendered as an empty box), whereas the latter (display: none) removes the element entirely from the render tree such that the element is invisible and is not part of the layout.
基于 Google web fundamental 中关于渲染树的解析,当元素的 display
属性为 none
时,该元素将完全从 render tree
中移除,并且该元素是不可见,且 不是 布局的一部分。
This value causes an element to not appear in the formatting structure (i.e., in visual media the element generates no boxes and has no effect on layout).
在 W3C CSS 标准中,对 display
为 none
的 描述,当该属性为 none
时,元素是不可见的,且 不生成 任何的盒模型,且 不 对布局产生影响最新草案。
那么,据上文的标准理论,本文所述的 “存在与元素相关联的 CSS layout box” 是指元素存在于当前 render tree
中,即 元素及其祖先元素 的 display 的值不为 none
。
scroll~ 系列属性
scroll~
系列属性可用于测量一个元素的 scroll area 的大小和 scroll area 相对于自身可见区域的位置信息。
scroll~ series | 只读 | 含义 |
---|---|---|
scrollTopMDN, W3C | —— | 元素的滚动区域相对于最近可见区域的 padding edge 的 y 值(若以 padding edge 为 y=0 位置) |
scrollLeftMDN, W3C | —— | 元素的滚动区域相对于最近可见区域的 padding edge 的 x 值(若以 padding edge 为 x=0 位置) |
scrollWidthMDN, W3C | ✔️ | 元素滚动区域#的宽度 |
scrollHeightMDN, W3C | ✔️ | 元素滚动区域#的高度 |
scrollTop
适用于测量 滚动区域 相对于 可视区域(Its topmost visible content)的 顶部 padding edge的距离。
Getter
Return the y-coordinate of the scrolling area at the alignment point with the top of the padding edge of the element# 9..
返回元素的顶部 padding edge 和滚动区域的对齐点的 y 坐标值(若以 padding edge 为
y=0
位置)。
展示一个元素 垂直方向已发生 滚动的距离的像素值。一个元素的 scrollTop
的值来源于该元素 content
区域到最顶级的 可见 内容区域(即滚动容器)的 padding edge#.9 的距离。当一个元素的内容区域 content
未生成垂直滚动条时,那么该元素的 scrollTop
的值恒为 0,具体的计算方式可见 W3C CSS view。
在 W3C CSS box model 规范中,明确指出一个元素的 padding edge 包围着一个元素盒子的
padding
。当设置给定的一边padding
为0
时,此时该边的 padding edge 与元素盒子的 content edge是一致的。四个方向的 padding edge 形成了一个padding box
。那么通俗地理解,
padding edge
指的是padding box
的四个边界。
Setter
直接赋值给元素的 scrollTop 可实现移动该元素的 垂直 滚动条的位置。特别地,该值不能为负值,否则为 0,且不能超出内容区域可滚动的最大值,否则为最大值。
在设置元素的 scrollTop
MDN, W3C 后,在未指定 scroll behavior
MDN, W3C 的情况下,将执行 scroll behavior: auto
(即立即滚动,而非平滑滚动),并滚动到 [element.scrollLeft, element.scroll.Top]
点。
具体的实现方式可见于 W3C CSS view - scrollTop 中 set
部分。
// 在当前页面生成滚动条时,即根元素的 `content` 区域生成垂直滚动条时,scrollTop 将变化
document.documentElement.scrollTop // 将展示当前页面滚动条的移动位置
// 由于历史原因存在以下兼容性解决方案
const nowLocation =
document.documentElement.scrollTop ||
window.pageYOffset || // window.scrollY 的别名
document.body.scrollTop
scrollLeft
适用于测量 滚动区域 相对于 可视区域(Its topmost visible content)的 左边 padding edge的距离。
Getter
Return the x-coordinate of the scrolling area at the alignment point with the left of the padding edge of the element# 9..
返回元素的左边的 padding edge 与(子级)滚动区域的对齐点处的 x 坐标值(若以 padding edge 为
x=0
位置)。
展示一个元素 水平方向已发生 滚动的距离的像素值。一个元素的 scrollLeft
的值来源于该元素 content
区域到最顶级的 可见 内容区域(即滚动容器)的 padding edge#.9 的距离。当一个元素的内容区域 content
未生成水平滚动条时,那么该元素的 scrollLeft
的值恒为 0,具体的计算方式可见 W3C CSS view。
Setter
直接赋值给元素的 scrollLeft
MDN, W3C 可实现移动该元素的 水平 滚动条的位置。特别地,该值不能为负值,否则为 0,且不能超出内容区域可滚动的最大值,否则为最大值。
在设置元素的 scrollLeft
MDN, W3C 后,在未指定 scroll behavior
MDN, W3C 的情况下,将执行 scroll behavior: auto
(即立即滚动,而非平滑滚动),并滚动到 [element.scrollLeft, element.scroll.Top]
点。
scrollWidth
Return the width of the element’s scrolling area.
返回 滚动区域# 的宽度。
只读 属性。描述了当前元素的内容 content box
区域的宽度,其中包含因溢出屏幕不可见的内容区域。
与 scrollHeight 相似,在不存在水平滚动条时,当前元素的 scrollWidth
等于 clientWidth
。且 scrollHeight 的值为一个 Math.round 的四舍五入近似值。
scrollHeight
Return the height of the element’s scrolling area.
返回 滚动区域# 高度。
只读 属性。描述了一个元素的内容区域的测量高度值。被测量的内容区域 包含 因为溢出屏幕而不可见的内容区域。
scrollHeight
等于在没有垂直滚动条时,元素在 viewport
内为了适应所有内容所需的最小高度。该高度以同样的方式被 clientHeight 测量:它包含了元素的 padding
,但不包含 border
,margin
或者水平滚动条(如果存在的话)。它同样包含了伪元素的高度,如 ::before
或 ::after
。 如果元素的内容区域可以被自动适应的情况下,且没有出现垂直滚动条时,scrollHeight 将等于 clientHeight。
This property will round the value to an integer. If you need a fractional value, use Element.getBoundingClientRect().
注: 该参数始终返回一个 Math.round 四舍五入取整的整数。如果需要小数位的值,可使用 Element.getBoundingClientRect()。
client~ 系列属性
-
clientTop 和 clientLeft 一般指 包含 滚动条宽高的指定边的
border
的宽度。 -
clientWidth 和 clientHeight 主要用于测量元素的 不包含 滚动条的
padding box
区域的宽高。
client~ series | 只读 | 含义 |
---|---|---|
clientTopMDN, W3C | ✔️ | 元素的 顶端 border 宽度加上元素的 顶端 的 padding edge 和 顶端 的 border edge 顶端之间渲染出的所有滚动条的 高度 |
clientLeftMDN, W3C | ✔️ | 元素的 左侧 border 宽度加上元素 左侧 padding edge 和 左侧 border edge 之间所有滚动条的 宽度 |
clientWidthMDN, W3C | ✔️ | 不包括垂直滚动条的 padding box 区域宽度,或没有发生水平滚动的 scrollWidth 宽度 |
clientHeightMDN, W3C | ✔️ | 不包括水平滚动条的 padding box 区域高度,或没有发生垂直滚动的 scrollHeight 高度 |
clientTop
Return the computed value of the border-top-width property plus the height of any scrollbar rendered between the top padding edge and the top border edge, ignoring any transforms that apply to the element and its ancestors.
只读 属性。返回 border-top-width
的计算值加上元素的顶端的 padding edge 和顶端的 border edge 之间渲染出的所有滚动条的 高度。并且 忽略 元素及其祖先元素的所有 transforms
效果。
即在没有滚动条的情况下,clientTop 是元素顶部 border
的 宽度。该属性只返回一个 四舍五入 的整数值,若需要一个精确值,应该使用 element.getBoundingClientRect()。
clientLeft
Return the computed value of the border-left-width property plus the width of any scrollbar rendered between the left padding edge and the left border edge, ignoring any transforms that apply to the element and its ancestors.
只读 属性。返回元素的 border-left-width
计算值加上在元素的左侧 padding edge 和 左侧 border-edge 之间渲染出的所有垂直滚动条的 宽度。忽略 所有应用在当前元素及其它的祖先元素上的 transforms
效果。
当 layout.scrollbar.side preference 设置(滚动条偏好)值为 1
或 3
,或当 text-direction
的值设置为 RTL
时,元素的垂直滚动条将布局在元素的 左侧,这将影响到元素的 clientLeft
MDN, W3C 的计算。
clientWidth
- If the element has no associated CSS layout box or if the CSS layout box is inline, return zero.
- If the element is the root element and the element’s node document is not in quirks mode, or if the element is the HTML body element and the element’s node document is in quirks mode, return the viewport width excluding the size of a rendered scroll bar (if any).
- Return the width of the padding edge excluding the width of any rendered scrollbar between the padding edge and the border edge, ignoring any transforms that apply to the element and its ancestors.
只读 属性。
- 当一个元素没有相关联的
CSS layout box
或CSS layout box
是行内盒模型时,返回 0。 - 当元素是根元素并且元素的 node document 不在 怪异模式 下,或元素是
<body>
元素且元素在 怪异模式 下,返回不包含滚动条宽度(如有)的视口宽度。 - 返回不包含在 padding edge 和 border edge 之间渲染出的滚动条的宽度的 padding edge 所包围形成的区域的宽度,并且忽略应用在元素及元素祖先上的任意
transforms
效果。
可使用以下伪代码公式计算一个元素的 clientWidth
MDN, W3C:
// 伪代码
const clientWidth =
element.height +
element.paddingLeft +
element.paddingRight -
verticalScrollbarWidth
clientHeight
Return the height of the padding edge excluding the height of any rendered scrollbar between the padding edge and the border edge, ignoring any transforms that apply to the element and its ancestors.
只读 属性。在没有 CSS layout boxes 或 inline layout boxes
的情况下,对于元素来说,该值为 0 。否则,等于元素的 inner height
的像素值。其中 包含 padding
但 不包含 border
、margin
或 水平滚动条。
可通过以下伪代码公式计算元素的 clientHeight
MDN, W3C:
// 伪代码
const clientHeight =
element.height +
element.paddingLeft +
element.paddingRight -
horizontalScrollbarWidth
This property will round the value to an integer. If you need a fractional value, use Element.getBoundingClientRect().
注: 该属性始终返回一个 Math.round 四舍五入取整的整数。如果需要小数位的值,可使用 Element.getBoundingClientRect()。
offset~ 系列
offset~ series | 只读 | 含义 |
---|---|---|
offsetParentMDN, W3C | ✔️ | 元素的最近包含该元素的定位元素的对象引用 |
offsetTopMDN, W3C | ✔️ | 元素距离最近 offsetParent 的顶端的距离 |
offsetLeftMDN, W3C | ✔️ | 当前元素的 左上角 的 border edge 顶点 相对于 offsetParent 节点左侧 border edge 顶点偏移 offset 的像素 |
offsetWidthMDN, W3C | ✔️ | 描述任意具有相关联 CSS layout box 元素的第一个 CSS layout box 的 border edge 形成的区域的 宽度,其中,不包含任意 伪元素 的宽度 |
offsetHeightMDN, W3C | ✔️ | 描述任意具有相关联的 CSS layout box 元素的第一个 CSS layout box 的 border edge 形成的区域的 高度,其中,不包含任意的 伪元素 的高度 |
块级元素的 offset~ 属性
对于块级元素来说,offsetTop
,offsetLeft
,offsetWidth
,offsetHeight
描述了一个元素的 border box 相对于 offsetParent 的偏移量。
行内元素的 offset~ 属性
对于存在换行 (wrap
) 的行内元素来说。offsetTop
和 offsetLeft
描述了与元素相关联的第一个 CSS layout box
的 border edge 左上角顶点相对于 offsetParent 的 y 和 x 轴偏移量,而 offsetWidth
和 offsetHeight
描述的是 bounding border box
的尺寸(整数值,通过 Element.getBoundingClientRect() 获取精确数值)。
因此,一个行内元素盒模型的 offsetTop
,offsetLeft
,offsetWidth
,offsetHeight
的 left
、top
、width
、height
并不会 包含换行的 CSS layout box
部分。
offsetParent
只读 属性。返回最近(指在包含层级上的最近)的定位(该包含元素的 position
值不为默认值)且包含该元素的元素的对象的引用。若元素没有定位,返回最近的 <td>
,<th>
,<table>
或 <body>
。
offsetTop 和 offsetLeft 都是相对于 offsetParent
的 padding edge 进行计算的。
元素的 offsetParent 计算方式如下#:
-
若满足以下任一情况,返回
null
并结束 offsetParent 的算法:- 若元素没有相关联的
CSS layout box
时; - 若元素是根元素
<html>
; - 若元素是
<body>
元素; - 若元素的 position 属性的计算值为
fixed
时。
- 若元素没有相关联的
-
涉及 shadow DOM 的计算方式可见于
W3C
原文章节 第二点。
offsetTop
只读 属性。展示当前元素相对于 offsetParent 节点顶端 top
的距离。
元素的 offsetTop 计算方法如下:
-
若元素的是
<body>
元素或没有相关联的CSS layout box
时,返回 0 并结束本算法。 -
若元素的 offsetParent 为
null
时,返回相对于 初始包含块 的源点,且与元素关联的 第一个CSS layout box
的顶部 border edge 的 y 坐标。并忽略所有应用在该元素及其祖先元素上的transforms
变换,并结束本算法。包含块 是一个用于形成与之相关的 大小(sizing) 和 定位(positioning) 的矩形区域(通常情况下指生成它的
box
的子级)。特别地,包含块并不是一个box
(它是一个矩形)。然而,它经常由一个box
的尺寸推导而来。如果一个包含块的属性被指定,那么就说它们同时也指定了 生成该包含块 的box
上的值。这些值除非特别指定,否则都是来自于 根元素 。初始包含块 是指根元素的 包含块,对于连续介质(
continuous media
)来说,它具有视口的尺寸。初始包含块的direction
属性是和根元素对应属性是一致的。 -
返回从相对于 初始包含快 的,且与元素相关联的第一个
CSS layout box
的顶端 border edge 的 y 坐标 减去 与元素的 offsetParent 相关联的第一个CSS layout box
的顶端 padding edge 的 y 坐标值。
注意:一个由多行盒模型(
multiple line boxes
)组成的行内元素仅仅计算它的第一个CSS layout box
。
offsetLeft
只读 属性。表示当前元素的 左上角 的 border edge 顶点 相对于 offsetParent 节点左侧 border edge 顶点偏移 offset
的像素。
元素 offsetLeft 具体实现如下:
-
若元素是
<body>
元素或没有相关联的CSS layout box
时,返回 0,并结束本算法。 -
若元素的 offsetParent 为
null
时,返回相对于 初始包含快 源点,且与元素相关联的第一个CSS layout box
的 左侧 border edge 的 x 坐标。忽略所有应用在元素及其祖先元素上的transforms
效果,并结束本算法。 -
返回相对于 初始包含块 源点,且与元素相关联的第一个
CSS layout box
的 左侧 border edge 的 x 坐标 减去 与元素的 offsetParent 相关联的第一个CSS layout box
的 左侧 border edge 的 x 坐标的结果。忽略所有应用在元素及其祖先元素的transforms
效果。Return the result of subtracting the x-coordinate of the left padding edge of the first CSS layout box associated with the offsetParent of the element from the x-coordinate of the left border edge of the first CSS layout box associated with the element, relative to the initial containing block origin, ignoring any transforms that apply to the element and its ancestors.
offsetWidth
只读 属性。计算方式如下#:
-
若元素没有相关联的
CSS layout box
那么返回 0 并结束本算法。 -
返回元素相关联的 第一个
CSS layout box
的 border edge 的 宽度,并忽略所有应用在元素及其祖先元素上的transforms
效果。
值得注意的是,offsetWidth 并不包含任意的 伪元素 尺寸,但包含任意的渲染出的垂直滚动条(如有)。
const offsetWidth =
bordersWidth + padding + verticalScrollbarWidth - pseudoElementWidth
offsetHeight
只读 属性,计算方式如下:
-
如果元素没有相关联的
CSS layout box
时,返回 0,并结束本算法。 -
返回与元素相关联的 第一个
CSS layout box
的 border edge 形成的区域的 高度,并忽略所有应用在元素及其祖先元素的transforms
效果。
同样,offsetHeight 的值不包含任意 伪元素 的尺寸,但包含任意渲染出的水平滚动条的 高度。
视图总结
- 非
document
的常规元素的垂直滚动的CSSOM
解析
- 包含
transform
变换的CSSOM
解析
document
的垂直滚动的CSSOM
解析