vh/vw 锚定 layout viewport 而非物理屏幕,受 viewport 设置影响;百分比依赖父容器高度,父元素 height 为 auto 时失效;100vh 在 ios safari 存在地址栏变化导致跳变问题,推荐用 100dvh 或 js 动态适配。

vh/vw 直接锚定视口尺寸,百分比锚定父容器——这是移动端适配中出问题最多的根源。
vh/vw 的计算基准是 Layout Viewport,不是屏幕物理像素
在移动端,vh 和 vw 的“视口”指 Layout Viewport(布局视口),它由 <meta name="viewport"> 的 width 和 initial-scale 决定,而非设备屏幕宽度或 DPR。比如 iPhone 14 的物理宽度是 1170px,但 Layout Viewport 默认是 980px(不设 viewport 时)或 390px(设 width=device-width 后)。所以 100vw 实际等于 Layout Viewport 宽度,不是设备像素宽度。
常见错误现象:
- 未设置
<meta name="viewport" content="width=device-width, initial-scale=1">,导致100vw比预期宽很多(如 980px),内容横向溢出 - 安卓某些浏览器(如旧版 UC)对
vmax/vmin支持不全,用vmin: 100vmin做横竖屏统一高度时 fallback 失效 - iOS Safari 在地址栏收起/展开时会触发
vh重算,导致100vh高度跳变(尤其在 fixed 元素中)
百分比单位依赖父元素,而父元素可能没有明确尺寸
在移动端,height: 50% 要生效,父元素必须有可计算的高度(非 auto)。但多数容器默认 height: auto,于是 50% 计算结果为 0 —— 这就是为什么“给子元素设 height: 100% 却没效果”的高频问题。
使用场景对比:
- 适合用
%:子元素需随父容器缩放(如 flex item 宽度、grid track 分配) - 适合用
vh/vw:需要撑满屏幕、做全屏背景、固定比例容器(如aspect-ratio: 16/9不兼容时用padding-top: 56.25%或height: 56.25vw) - 特别注意:
position: fixed元素的top/right/bottom/left值用%时,参照的是视口,不是父元素 —— 这是唯一例外
性能与兼容性差异:vw/vh 更轻量,但 iOS Safari 有渲染 bug
vw/vh 是 CSS 原生单位,无需 JS 计算或媒体查询,浏览器直接解析,性能优于 rem + JS 动态改根字体。但 iOS Safari(直到 iOS 16.4)存在一个经典 bug:100vh 在地址栏隐藏后仍按初始视口高度计算,导致底部被遮挡。
实操建议:
- 避免单独依赖
100vh布局关键区域;可用100dvh(新标准,Safari 16.4+ 支持)替代,dvh表示“动态视口高度”,会响应地址栏变化 - 兼容老版本 Safari:用 JS 获取
window.innerHeight设置自定义 CSS 变量,再用calc(var(--vh, 1vh) * 100) - 不要在动画中高频修改
vw/vh值(如 scroll 触发的 resize),它们本身不触发重排,但若配合 transform 或 layout 触发属性,可能意外卡顿
实际写法中容易忽略的边界条件
很多人以为 100vh 就等于“屏幕可视区高度”,但实际还受以下影响:
- 页面存在横向滚动条时,
100vw包含滚动条宽度(约 16px),导致容器略宽于可视区 - 使用
overflow-x: hidden抑制滚动条后,100vw才真正对齐视口左边缘 -
vmin和vmax对横竖屏切换友好,但 Android WebView 4.x 及更早版本完全不支持,需降级为媒体查询 +vw/vh - 在 uni-app 或小程序中,
vh行为可能被宿主环境劫持(如微信小程序基础库 2.25.0+ 才支持vh),不能无脑复用 H5 逻辑
最常被忽略的一点:视口单位在打印媒体(@media print)中无效,如果项目需打印支持,vh/vw 必须配合 @supports 或媒体查询做 fallback。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











