不能混用svh、lvh、dvh,因三者基准不同:svh是静态最小高度,lvh是静态最大高度,dvh是动态实时高度,混用会导致布局错乱、重叠或留白。

混用不同基准单位会直接破坏布局
常见错误现象是写 height: 100dvh 同时又加 padding-bottom: 20svh,结果高度不可控。因为 dvh 是实时值,svh 是固定最小值,两者计算基准完全不同,浏览器不会自动对齐或换算。
使用场景里最容易踩坑的是带固定底栏的全屏页:有人想“主区用 dvh,底栏预留 svh 高度”,但实际运行中底栏可能被键盘顶起、或地址栏状态突变,导致重叠或留白。
- 同一元素内避免混用
svh/lvh/dvh - 父子容器若分别用不同单位,需确认父容器是否设置了
contain: layout或overflow: hidden,否则子级动态变化可能触发父级重排异常 - 涉及动画(如
transform: translateY(-100dvh))时,dvh值在滚动/键盘弹出过程中会跳变,动画可能中断或错帧
@supports 检测写法不对就等于没检测
很多开发者写成 @supports (height: 100dvh) 或 @supports (dvh: 1),这两种都无效。规范只认 @supports (min-height: 100dvh) 这一种写法——必须是属性+值的完整声明,且属性得是支持该单位的可设属性。
不写对检测,CSS 就会直接忽略整个块,降级到 100vh,而你在 iOS Safari 上一滚动,页面就跳。
立即学习“前端免费学习笔记(深入)”;
- 正确写法只有:
@supports (min-height: 100dvh) - 检测多个单位要分开写:
@supports (min-height: 100dvh) and (min-height: 100svh) - 不要在
@supports里写display: grid这类无关属性,它不会提升兼容性,反而干扰判断
svh 和 lvh 不是“更稳的 dvh”,而是静态边界
有人以为 svh 是 dvh 的保守版、lvh 是激进版,其实完全不是。它们三个根本不在一个维度上:svh 和 lvh 是静态值,初始化后永不响应滚动或键盘;dvh 才是唯一真正动态的。
典型误用:用 100lvh 做启动页,结果用户刚打开页面,地址栏还展开着,内容直接溢出屏幕底部——因为 lvh 根本不管当前状态,它只按“地址栏已收起”算。
-
svh适合按钮、输入框等必须始终可见的 UI 元素 -
lvh只适合无交互、纯展示型全屏页(如 splash screen),且要确保首次加载时地址栏大概率已隐藏 -
dvh是大多数场景的默认选择,但要注意键盘弹出时它的值会骤减,需配合visualViewportAPI 做微调
移动端键盘弹出会同时影响 dvh 和 svh/lvh
键盘弹出时,iOS Safari 和 Android Chrome 都会收缩可视区域,但行为不一致:dvh 会实时缩小,而 svh 和 lvh 不变——这导致原本用 svh 预留的底部空间,在键盘弹出后可能变得过大;而用 dvh 的容器则可能把输入框挤出视口。
这不是 bug,是设计如此:键盘属于 UA interface,但它不参与 svh/lvh 的初始假设,却会触发 dvh 更新。所以仅靠单位本身无法解决键盘遮挡问题。
- 不能只依赖
100dvh+scrollIntoView来防遮挡 - 需要监听
visualviewport.resize事件,动态调整margin-bottom或transform - Android Chrome 对
dvh在键盘场景下的更新有约 100ms 延迟,iOS 更快但仍有抖动
visualViewport API 的配合时机——dvh 变了,但 JS 拿到的 visualViewport.height 可能还没同步,差几帧就会导致布局闪动。


















