必须用@supports包裹整条规则,因iOS 15及更早版本不支持100dvh会忽略该声明导致页面塌陷;裸写min-height: 100dvh或仅包值会使新旧Safari均失效,正确写法是先设min-height: 100vh兜底,再用@supports块覆盖。

直接用 min-height: 100dvh 并配 @supports 降级,是当前最轻量、最可靠的解法;但裸写或写错包裹方式,反而会让新旧 Safari 都失效。
为什么 100dvh 必须用 @supports 包裹整条规则
iOS Safari 16.4+ 和 Chrome 105+ 才原生支持 100dvh,旧版(尤其是 iOS 15.x 及微信 WebView)会直接忽略该声明。如果只写:
.page {<br> min-height: 100vh;<br> min-height: 100dvh; /* 错误:老 Safari 忽略这行,新 Safari 仍用上一行 */<br>}结果是所有 Safari 都走 100vh,问题照旧。
-
@supports必须包裹整个 CSS 规则块,不能只包值 - 兜底声明(
min-height: 100vh)必须写在@supports外面,确保老环境至少有基础高度 - 优先用
min-height而非height,避免内容超长时被截断
标准写法:
立即学习“前端免费学习笔记(深入)”;
.page {<br> min-height: 100vh;<br>}<br>@supports (min-height: 100dvh) {<br> .page {<br> min-height: 100dvh;<br> }<br>}position: absolute 元素套 100dvh 为啥没反应
绝对定位元素的百分比高度(包括 100dvh)依赖包含块(containing block)的高度,不是“强制占满屏幕”。常见于弹窗、遮罩层、底部固定按钮。
- 父容器(如
body或直接祖先)没设min-height: 100dvh或显式高度 → 子元素100dvh实际计算为 0 - 别对绝对定位元素用
height: 100dvh,改用top: 0; bottom: 0;更可靠 - 若父容器本身也靠
--vh驱动,需确保它先完成初始化,否则子元素读到的是初始 1px
兼容 iOS 15 及以下必须用 JS 动态设 --vh
当用户存量含大量 iOS 15.x 或旧版 WebView 时,100dvh 会完全失效,页面塌成一条线。此时需 JS 回退:
- 必须在
DOMContentLoaded后立即执行一次,否则首屏渲染用的是地址栏未收起时的错误初始值 - 监听
visualviewport.resize事件,而非window.resize—— 后者不触发键盘弹起变化 - 初始值要兜底:
document.documentElement.style.setProperty('--vh', `${window.innerHeight * 0.01}px`) - 安卓部分定制系统(如华为 EMUI)
visualViewport.height返回异常,需加校验:if (v.height > 0 && v.height
CSS 中使用:height: calc(100 * var(--vh));(注意不是 100vh)
别把 --vh 当全局常量用
它只适合控制“容器级高度”,比如全屏页、模态框、固定定位导航栏。以下场景容易翻车:
- 嵌套滚动区域里用
--vh算子元素高度 → 子元素实际高度受父容器overflow和滚动影响,和视口无关 - 动画中用
--vh做transform: translateY()→ 视口变化时动画会跳帧,视觉撕裂 - 服务端渲染(SSR)页面首次加载时,JS 未执行,
--vh是空值,需 fallback 到100vh或100dvh
真正需要动态响应的,不是所有高度,而是那些紧贴视口边缘、参与交互的关键容器——多一层判断,比全局替换更稳。


















