背景

前端「宽与高」速查:视口、文档、元素与 CSS 单位

发表于 2026/05/07 18:00
🌺 摘要
从 innerWidth 到 scrollHeight,从 getBoundingClientRect 到 Visual Viewport;对照一张心智表分清「布局盒」「可见区域」「滚动尺寸」与移动端动态工具栏下的视口单位。

移动端适配、全屏弹层、自定义滚动容器时,「宽度」「高度」一词往往指的不是同一件东西:浏览器窗口布局视口视觉视口文档流元素盒模型各自有一套可读尺寸。下面按脚本可读 APICSS 单位两块归纳,便于对照选用。


1. window:与「窗口」相关的尺寸

API含义
window.innerWidth / innerHeight视口(viewport)内部宽高,包含滚动条占用的区域(若出现经典滚动条)。常用于「当前可见布局区域」的近似。
window.outerWidth / outerHeight整个浏览器窗口外沿(含标题栏、工具栏等因浏览器/系统而异的部分)。少用于布局,多用于诊断。
window.devicePixelRatio设备像素比,不是「宽度」本身,但影响 CSS 像素 ↔ 物理像素 的换算;高清屏上为 2、3 等。

与「文档有多长」无关:inner* 只描述窗口里的那块视口,文档可能比它高很多。


2. screen:物理屏幕与可用区域

API含义
screen.width / screen.height屏幕分辨率(设备相关,单位逻辑像素侧通常与系统报告一致)。
screen.availWidth / screen.availHeight扣除系统任务栏、Dock 等之后的可用区域。

一般不参与页面布局,偶尔用于大屏 kiosk、 Electron 或统计。


3. document / documentElement / body:文档与根元素

页面真实「内容有多宽多高」,要看根元素body(与浏览器怪异模式有关,现代标准下以 document.documentElement 为主)。

document.documentElement(即 <html> 与常见块级 body

属性典型含义
clientWidth / clientHeight内容区 + padding,不含滚动条、不含 border;可视区域内能「容纳」的客户端尺寸,受视口与样式影响。
offsetWidth / offsetHeight见下文 「offset 专节」:本质是 border box 的布局宽高(整数像素),不含 margin
scrollWidth / scrollHeight可滚动内容的总宽高(含溢出不可见部分)。scrollHeight 常用来判断「整页内容高度」。

记忆口诀:

  • client:看「padding 以内的可视区域」有多大(还要再扣掉元素上的滚动条);
  • offset:看「border box 在布局里占了多少宽/高」;
  • scroll:看「如果全部展开,内容一共多大」。

offsetWidth / offsetHeight 到底量的是什么

在标准盒模型下,可以把它们理解成 CSS 的 border box 外沿之间的间距(单位:CSS 像素),并且是 向零取整后的整数

  • offsetWidthborder-left + padding-left + 内容区宽度 + padding-right + border-right
  • offsetHeight ≈ 上、下方向的 border + padding + 内容区高度

因此:

  • 不包含 margin。外边距不参与「元素自身报告的宽高」。
  • 包含 borderpadding。改大 border 会直接推高 offset*
  • transform 无关scalerotate 等只影响绘制与 getBoundingClientRect()不改变 offsetWidth / offsetHeight(它们反映的是布局尺寸,不是屏幕上变形后的包络)。
  • position 无关offset* 不是坐标,只是宽高。

只问一句:offset* 包不包含滚动条?

  • 包含——前提是这个滚动条画在当前元素自己身上,且是占位式(经典)竖条/横条:它会占掉 border 内侧的一块厚度,算进 offsetWidth(常见是纵向条占宽度)或 offsetHeight横向条占高度)。
  • 对照:clientWidth / clientHeight 不包含这条滚动条,量的是「扣掉滚动条之后、padding 以内的可视区域」;所以 offset* - client* 在只有一条经典滚动条时,常被用来估算滚动条粗细
  • 例外:系统/浏览器用 overlay 滚动条(不挤占布局、浮在内容上方)时,可能几乎不占布局宽度,offset*client* 的差会变小;移动端、macOS「覆盖滚动条」等以本机实测为准。

clientWidth / clientHeight 对比(仅记关系即可):

  • client*:大致是 padding box 内侧的可视宽高,减去元素上的滚动条,不含 border
  • offset*border box 总宽高,含 border,对滚动条的处理与 client* 不同,所以二者之差不总是「两倍的 border」,需要结合是否有滚动条判断。

offsetLeft / offsetTop / offsetParent(顺带)

与「宽高」配套的定位读数:

  • offsetParent:作为偏移参照的最近一层定位父级positionstatic 的祖先,或 table/td/thbody 等规则,详见 MDN)。
  • offsetLeft / offsetTop:当前元素 border box 左上角相对 offsetParent 的 padding 内侧的偏移(同样大致对应布局,不受 transform)。

要做「相对视口」的碰撞检测,仍优先 getBoundingClientRect()offset* 家族更适合 「布局尺寸 / 相对 offsetParent 的排版位置」


4. 普通元素:同一套 client / offset / scroll

任意 HTMLElement 上三类属性与上一节同名:度量的是当前元素自身的盒,不是相对视口。

额外常用:

API含义
element.getBoundingClientRect()相对视口left/top/right/bottom/width/height(浮点,受 CSS 变换影响)。滚动后也会变,是「此刻屏幕上在哪」的首选。
window.scrollY / scrollX(或 pageYOffset文档纵向/横向已滚动距离,与 getBoundingClientRect 配合可算「相对文档」的位置。

offsetWidthgetBoundingClientRect().width 何时不一致:前者是未变换的布局 border box 整数宽;后者是变换后在视口中的轴对齐包络宽(可非整数)。做动画缩放时用后者;做「占栅格多宽」时用前者。


5. Visual Viewport:移动端地址栏、缩放与虚拟键盘

移动浏览器里,布局视口与「用户眼睛看到的区域」可能不一致。window.visualViewport(若存在)描述视觉视口

属性含义
width / height当前视觉视口 CSS 像素尺寸(会随缩放、地址栏显隐、键盘弹出等变化)。
offsetTop / offsetLeft视觉视口相对布局视口的偏移。
scalepinch 缩放因子。

监听 resizescroll 可做:键盘顶起输入框、固定底栏避让等。详见 MDN:Visual Viewport API


6. CSS 长度与视口单位

单位含义
pxCSS 像素,布局基础单位。
%相对包含块对应维度;高度链路上若父级未定义高度,容易出现「百分比无效」。
vw / vh视口宽/高的 1%。经典问题:移动端 100vh 常包含「地址栏收起前后」不一致的区域,导致整屏高度跳动。
svh / lvh / dvh(现代浏览器)视口、视口、动态视口高度:dvh 随工具栏显隐变化,更接近「当前可见高度」;svh 偏保守(偏小),lvh 偏大。
vmin / vmaxvwvh 中较小/较大者的 1%。

工程上:全屏一屏高优先尝试 100dvh(并配 100vh 回退),比单用 vh 稳。


7. 选用建议(很短)

  1. 「浏览器窗口里可见区域有多大」window.innerWidth/innerHeight;移动端精细行为 → visualViewport
  2. 「整页内容总高度」document.documentElement.scrollHeight(注意 bodyhtml 的 margin/高度样式)。
  3. 「border box 在布局里占多宽」(含 border/padding、整数、不吃 transform)→ offsetWidth「当前在视口里画出来多大」(浮点、吃 transform)→ getBoundingClientRect()
  4. CSS 全屏高度 → 优先 dvh,兼容层用 vh + min-height: -webkit-fill-available 等老方案按需补。

8. 小结表

层级典型读取方式
窗口视口innerWidth/innerHeight
视觉视口(移动)visualViewport.width/height
文档滚动尺寸document.documentElement.scrollWidth/scrollHeight
元素布局盒offsetWidth/offsetHeight
元素视口矩形getBoundingClientRect()
样式一屏高100dvh(+ 100vh 回退)

把「相对谁」(视口、文档、父元素、布局盒)先想清楚,再选 API 或单位,一般就不会和「宽度对不上」这类问题缠斗太久。

文章发表于 2026/05/07 18:00
上一篇 Let’s Encrypt 证书申请与 Nginx 配置实战
下一篇 window.dispatchEvent:在浏览器里派发与消费自定义事件

评论

加载中...