100dvh是标准解法但非万能:ios 16.4+支持,旧版需用@supports包裹整条规则并前置100vh兜底;absolute元素依赖包含块高度,应改用top:0;bottom:0;;兼容ios 15及以下须js动态设--vh变量并监听resize防抖更新。

移动端 100vh 在 Safari 失效,不是 bug,是 Safari 故意把 vh 锚定在初始布局视口(含地址栏)上,而用户实际看到的可视区域会随地址栏收起/键盘弹出动态变化——所以你写的 min-height: 100vh 在滚动后可能撑不满,height: 100vh 又可能截断内容。
为什么不能直接用 100dvh 就完事
100dvh 确实是标准解法,iOS Safari 16.4+ 已支持,但它不是万能钥匙:
- 你的用户里有 iOS 15.x 或更早系统?
100dvh会被完全忽略,降级成auto高度,页面直接塌掉 - 只写
height: 100dvh不加兜底,老浏览器连 fallback 都没有 - @supports 必须包裹整条规则,不能只包声明值:错写成
height: 100vh; height: 100dvh;会导致旧 Safari 保留100vh(看似正常),但新 Safari 因解析顺序仍用100vh,没触发dvh - 如果元素是
position: absolute且父容器没设高度,100dvh会失效——它依赖包含块,不等于“强制占满屏幕”
用 --vh 变量动态绑定 window.innerHeight
这是兼容 iOS 15 及以下的最稳路径,核心是让 CSS 能“感知”实时可视高度:
- 必须在
DOMContentLoaded后立即执行一次,否则首屏渲染用的是错误初始值 - 监听
resize事件就够了,orientationchange在部分 iOS 版本中不可靠;地址栏显隐、键盘弹起都会触发resize - 要防抖:iOS 连续触发
resize,直接更新样式会导致重排抖动,用requestAnimationFrame最稳妥 - CSS 中写
height: calc(var(--vh, 1vh) * 100),其中1vh是兜底,避免 JS 未加载时整个元素缩成一条线 - 别忘了给
html和body设margin: 0和height: 100%,否则window.innerHeight可能被外边距干扰
为什么 visualViewport.height 不是首选
虽然 visualViewport.height 比 window.innerHeight 更精准(能响应键盘弹起),但它有硬伤:
- iOS Safari 15.4 才开始支持
visualViewport,15.0–15.3 会undefined,必须降级到innerHeight -
visualViewport在页面刚加载时可能为null,需加判断,否则报错中断 JS - 监听
visualviewport.resize事件比监听window.resize更细粒度,但兼容性差:Safari 15.4+ 支持,Chrome 61+ 支持,Firefox 不支持 - 多数场景下
window.innerHeight已足够——键盘弹起时,Safari 仍会触发resize,只是延迟约 100–300ms,加setTimeout防抖即可覆盖
真正容易被忽略的是:绝对定位元素 + vh 类单位,本质上是无效组合。与其纠结怎么让 100vh 在 position: absolute 下生效,不如直接用 top: 0; bottom: 0;——它不依赖父容器高度,也不受视口单位缺陷影响。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











