lvh/svh 在 safari 16.4+、chrome 109+、firefox 117+(需手动开启)中部分支持,微信/x5、旧版 webview 等不识别;@supports 必须独立成块且用 and (not ...) 避免覆盖;css 变量 fallback 仅解决初始兼容,不响应键盘变化;安卓及微信环境需 js 补位。

lvh/svh 在 Safari、Chrome、Firefox 中的实际支持差异
目前 lvh 和 svh 在主流移动端浏览器中并非“全量可用”,而是存在明确的版本断层和内核差异。Safari 16.4+(iOS 16.4+)原生支持;Chrome 109+(Android 12+ 及较新 WebView)开始稳定启用;Firefox 117+ 需手动开启 layout.css.dvh-units.enabled 标志,微信内置浏览器(X5 内核)、QQ 浏览器(Trident/QQ 内核)、旧版 Android WebView 基本不识别——直接写 height: 100svh 会导致高度塌为 0 或回退到 auto。
@supports 检测必须写成独立规则块,不能嵌套
很多人误以为 @supports (height: 100svh) 可以放在已有选择器内部,或与媒体查询混用。这是无效语法,浏览器会忽略整个块。正确做法是:每个单位检测必须单独成块,且仅包裹具体声明:
section.hero { height: 100vh; }
@supports (height: 100svh) {
section.hero { height: 100svh; }
}
@supports (height: 100lvh) and (not (height: 100svh)) {
section.hero { height: 100lvh; }
}
注意两点:不能写 @supports (height: 100svh) { section.hero { ... } } 套在另一个规则里;and (not (height: 100svh)) 是必要兜底,避免 Chrome 109+ 同时匹配两个规则导致覆盖冲突。
用 CSS 自定义属性做 fallback 时,值不能带单位参与计算
有人尝试这样写:--vh: 100svh; height: var(--vh); —— 看似简洁,但问题在于:自定义属性一旦被设为 100svh,就无法再通过 @supports 动态切换其值;更关键的是,var(--vh) 在不支持的浏览器中不会降级为 100vh,而是保持字符串原样,最终解析失败。
可行方案是分层定义:
- 先用
:root { --vh: 100vh; }设默认值 - 再用
@supports (height: 100svh) { :root { --vh: 100svh; } }覆盖 - 最后所有用到的地方统一写
height: var(--vh);
但必须注意:CSS 自定义属性本身不触发重排,但它的值变更不会自动通知已渲染元素更新高度——所以首次加载后切换键盘/地址栏状态,var(--vh) 不会响应式重算。它只解决“初始加载时的单位兼容”,不替代 dvh 的动态能力。
安卓低端机和微信环境必须 JS 补位,不能只靠 CSS
微信内置浏览器(X5 内核 v8.0.x 及以下)、部分国产厂商定制 WebView(如华为 EMUI 12 旧版)对 lvh/svh 完全无反应,@supports 也返回 false。此时纯 CSS 方案必然失效。
最小成本补位逻辑:
- 监听
focus事件,在输入框获得焦点后,延时 100ms 读取visualViewport?.height(若存在)或window.innerHeight - 将该值存入
:root的style属性:document.documentElement.style.setProperty('--dynamic-vh', `${height}px`) - CSS 中用
height: var(--dynamic-vh, 100vh);回退
不要依赖 resize 事件判断键盘——安卓上它常不触发;也不要直接用 innerHeight 差值估算键盘高度,误差常达 ±100px。
真正麻烦的不是写对一个单位,而是意识到 svh 和 lvh 是锚点值,不是实时传感器;它们解决的是“静态错位”,而非“动态响应”。需要键盘弹出时内容自动上推、按钮上浮、滚动区收缩——这些仍得靠 env(keyboard-inset-bottom)(iOS)或 JS + visualViewport(安卓)组合实现。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











