应优先使用100dvh替代100vh实现动态视口适配,但必须前置100vh作为降级;因100vh是静态单位,工具栏切换时高度不变导致布局跳动,而100dvh响应可视区域变化,需注意兼容性、js不可读取像素值、不支持@media及部分webview等限制。

直接用 100dvh 替代 100vh,但必须前置 100vh 作为降级,且不能依赖它解决所有场景。
为什么 100vh 在工具栏切换时会跳动
因为 100vh 是静态值:浏览器在页面加载瞬间按当时视口高度(含地址栏)算出 1vh = Xpx,之后无论地址栏收起还是弹出,这个像素值都不变。工具栏收起后实际可用高度变大,但元素仍按旧高度撑开,导致上移、留白或被截断——不是渲染 bug,是单位定义本身就不响应变化。
用 100dvh 替换的正确写法
必须把兼容声明写在前面,否则不支持的浏览器会直接丢弃整个规则:
section.fullscreen {
height: 100vh; /* iOS Safari
-
100dvh不是补丁,是标准单位,代表「当前可视区域高度」,地址栏一动它就重算 - 不能写成
height: 100vh, 100dvh—— CSS 不允许逗号分隔不同单位值 -
@supports (height: 100dvh)可以用,但没必要绕一圈;直接层叠更简洁、更可控 - 构建工具(如 PostCSS)若自动转换单位,要关掉对
dvh的处理,否则可能错误降级为vh
100dvh 的硬限制和易踩坑点
它解决的是“动态适配”,但不是万能胶水:
-
getComputedStyle(el).height返回的是字符串"100dvh",不是像素值,无法用于 JS 计算 - 不能用在
@media查询里,比如@media (min-height: 100dvh)语法非法 - 某些安卓 WebView 或微信内置浏览器尚未透出
dvh支持,会静默回退到前一条100vh - 首次滚动后才生效(尤其 Safari 16.4 初期版本),首屏可能闪一下——所以仍需搭配
viewport-fit=covermeta 和初始 resize 触发
什么情况下不该只靠 100dvh
真正麻烦的不是单位换不换,而是需求是否真需要“绝对占满当前视口”:
- 全屏轮播容器更适合
min-height: 100dvh; height: auto,让内容自然撑开,避免文字多时被裁 - 固定底部按钮别死磕
bottom: 0; height: 100dvh,改用bottom: clamp(1rem, 5svh, 2rem)更稳 - 弹层遮罩必须覆盖全部可视区域?
100dvh是首选,但若需支持 iOS 15,就得加 JS 监听visualViewport动态设--dvh
最常被忽略的一点:dvh 解决的是“高度值更新”,但不保证重排时机。如果父容器没触发 layout,子元素即使用了 100dvh 也可能卡在旧位置——这不是单位问题,是渲染流水线的事。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











