getBoundingClientRect() 的 width/height 包含 content + padding + border,不含 margin;受 transform 影响,返回变换后实际像素尺寸;display: none 时全为0,visibility: hidden 不影响;单位为四舍五入像素。

getBoundingClientRect() 返回的 width/height 包含哪些部分
getBoundingClientRect() 返回的是元素在视口中的**实际渲染尺寸和位置**,其 width 和 height 属性等于 content + padding + border,但**不包含 margin**。这是最常被误读的一点:很多人以为它返回“总占用空间”,其实 margin 是外侧的、不影响自身盒模型几何计算的偏移量,浏览器压根不会把它算进 width/height 里。
使用场景主要是做定位、拖拽边界判断、滚动对齐——这时候你真正需要的是“这个盒子此刻在屏幕上占多大一块”,而不是“它理论上该占多大”。
- 如果元素有 transform(比如
scale(0.8)),getBoundingClientRect()返回的是变换后的实际像素尺寸,不是 CSS 声明值 - 它受 display: none 影响:
display: none的元素调用会返回全为 0 的对象 - 它不受 visibility: hidden 影响,仍返回正常尺寸
- 注意单位永远是像素(px),且是四舍五入后的整数(高 DPI 下可能有小数,但多数情况可视为整数)
offsetWidth / offsetHeight 和 clientWidth / clientHeight 的区别
offsetWidth 和 offsetHeight 返回的是元素的**布局尺寸**:包括 content + padding + border,同样**不含 margin**;而 clientWidth/clientHeight 只含 content + padding,连 border 都不算进去。
关键差异在于 scrollbars:如果元素有滚动条且未隐藏(如 overflow: auto 且内容溢出),clientWidth 会减去滚动条宽度(在 Windows 常见),而 offsetWidth 不会——它把滚动条当成内容区一部分来占位。
立即学习“前端免费学习笔记(深入)”;
-
offsetWidth会触发同步回流(reflow),频繁读取影响性能,尤其在动画帧中要小心 -
clientWidth同样触发回流,但值更“保守”,适合测可视区域大小(比如判断是否出现横向滚动) - 两者都不包含 margin,也都不受 transform 影响(返回的是布局树中的原始尺寸)
如何真正拿到“content + padding + border + margin”的总和
浏览器没有现成 API 直接返回这个总和,因为 margin 不属于该元素的“占据空间”范畴——它是作用于外部布局的,且可能被相邻 margin 合并(margin collapse)。所以你要自己算,但得先明确:你到底要哪一层的“总和”?
- 若目标是**预测该元素对父容器高度/宽度的影响**:用
offsetHeight+getComputedStyle拿marginTop和marginBottom(注意解析为数值,单位要转) - 若目标是**判断两个相邻块级元素之间的净距离**:必须考虑 margin collapse,不能简单相加;此时应直接用
getBoundingClientRect()算两个元素top或left的差值 - 注意
getComputedStyle返回的 margin 值可能是auto,此时无法转成像素,需结合offsetParent和定位逻辑推断 - margin collapse 只发生在块级、普通文档流、垂直方向(上下 margin)、相邻兄弟或父子间,flex/grid 容器子项不发生 collapse
常见错误:用 getComputedStyle 直接加总所有 box-sizing 相关属性
有人会写:parseInt(getComputedStyle(el).width) + parseInt(...) + ...,这几乎一定出错。原因很实在:
-
getComputedStyle(el).width返回的是 content 宽度(当box-sizing: content-box)或 border-box 宽度(当box-sizing: border-box),它本身已经隐含了 padding/border 的归属逻辑 - 你再手动加
paddingLeft、borderLeftWidth,就重复计算了 - 更麻烦的是,
getComputedStyle返回的值带单位(如"12px"),直接parseInt会截断,遇到"auto"或"calc(100% - 20px)"就彻底失效 - 真正稳定的做法是:优先用
offsetWidth或getBoundingClientRect().width作为基准,再按需叠加 margin(仅当你明确知道 margin 未 collapse 时)
margin collapse 是最容易被忽略的复杂点——你以为加了 margin 就一定撑开距离,结果在父子或兄弟间它消失了。真要精确控制间距,要么用 padding,要么用 flex gap,要么显式设置 overflow: hidden 阻断 collapse。事情说清了就结束










