首选100dvh,--vh变量方案仅为兜底;需动态监听resize与scroll事件并用requestanimationframe节流,初始化必须在domcontentloaded前执行,且--vh须赋值为window.innerheight*0.01的px值,css中fallback必须用绝对单位如1px,不可用1vh参与calc运算。

直接用 100dvh 是首选,--vh 变量方案只是兜底——它必须配合 requestAnimationFrame 节流、resize + scroll 双监听、且 CSS 中的 calc() 写法稍错就会彻底失效。
为什么不能只在 DOMContentLoaded 里设一次 --vh
移动端地址栏收起、软键盘弹出、横竖屏切换都会改 window.innerHeight,但 CSS 变量不会自动更新。只初始化一次,后续所有布局就基于那个过期值。比如横屏切回竖屏后,--vh 还是旧宽高比对应值,导致元素被拉伸或底部留白。
- 必须监听
resize事件(orientationchange在 iOS 上不稳定) - 某些 iOS 版本地址栏收起时不触发
resize,需额外监听scroll,但要用requestAnimationFrame节流,避免卡顿 - 首次执行必须在
DOMContentLoaded前或刚进脚本就调用,否则白屏阶段用的是1px兜底,可能闪动
--vh 的正确赋值和 CSS fallback 写法
--vh 必须是带 px 单位的数值,且是 window.innerHeight * 0.01(即 1% 高度),不是直接塞 vh 单位;CSS 中用 calc(100 * var(--vh, 1px)),且 fallback 必须是绝对单位(如 1px),不能是 1vh——因为 1vh 是相对单位,无法参与 calc 数值运算。
- JS 正确写法:
document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`) - CSS 正确写法:
min-height: calc(100 * var(--vh, 1px)); min-height: 100dvh; min-height: 100vh; - 千万别写
calc(var(--vh, 1vh) * 100)——1vh会被忽略,整条声明失效
为什么 env(height) 比 JS 方案更干净
iOS 11+ / macOS Monterey+ 支持 env(height)(也叫 env(safe-area-height)),它返回当前可用视口高度,且不会随滚动抖动。相比 JS 监听,它无延迟、不闪动、不增加 LCP 压力。
- 必须用
@supports (height: env(height))包裹,否则非 Safari 浏览器会把整条声明当无效值丢弃 - 不要写成
--vh: 100vh, env(height)——CSS 变量不支持逗号分隔 fallback - 推荐组合:
:root { --vh: 100vh; } @supports (height: env(height)) { :root { --vh: env(height); } }
绝对定位元素为啥设了 min-h-[100dvh] 还没反应
百分比高度(包括 100dvh)依赖包含块(containing block)的高度,不是“强制占满屏幕”。常见于 fixed 弹窗、抽屉菜单、底部按钮等场景:
- 父容器(如
body或直接祖先)没设min-h-[100dvh]或显式高度 → 子元素的100dvh实际计算为0 - 别对
position: absolute/fixed元素用height: 100dvh,改用top-0 bottom-0更可靠(它不依赖父容器高度) - 侧边栏用
fixed时,必须加inset-y-0 left-0,而不是仅inset-0,避免 RTL 或其他定位干扰
真正容易被忽略的点是:哪怕你写了 min-h-[100dvh] flex-1,若父容器没 flex flex-col,flex-1 就没空间可分,主区域照样塌陷;而构建工具如 PostCSS 若自动把 dvh 降级为 vh,必须关掉该插件(例如 postcss-100vh-fix),否则白忙一场。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











