我用 100vh 写的 H5,在 Android 上被软键盘"顶穿"了 😭

事情是这样的。
我用 height: 100vh 写了一个很普通的 H5 页面,
结构也很常规:上面是内容,下面是输入框。
在 iOS 上一切正常,
结果一到 Android,用户一点输入框------
👉 软键盘弹起,输入框直接被挡住。
那一刻我意识到:
又是 100vh 的锅。
问题复现:看起来很合理,其实已经埋雷了 💣
css
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
ini
<input placeholder="请输入手机号" />
现象是这样的:
-
Android 软键盘弹起
-
页面视觉高度明显变小
-
但 .page 仍然是 100vh
-
👉 输入框被键盘盖住,页面不滚动
用户:看不见怎么输?****
我:......****
深挖原因:不是你代码写错,是
100vh
理解错了 🤯
很多人(包括我以前)都会默认:
vh = 当前可视区域高度
但在 Android 浏览器 / WebView 里,真实情况是:
-
vh 取的是 初始布局视口高度
-
软键盘弹起:
-
改变的是"可视区域"
-
不会重新计算 vh
-
一句话总结:
键盘变了,vh 没变。
所以你看到的就是:
- 页面下面被键盘盖住
- CSS 还以为自己是"满屏"
那些年我试过但不太靠谱的方案 🙃
❌ 方案一:监听
resize
javascript
window.addEventListener('resize', () => {
// 动态改高度
});
问题:
- 有的 Android 触发,有的不触发
- WebView 行为更是五花八门
- 维护成本很高
❌ 方案二:
scrollIntoView
css
input.scrollIntoView({ behavior: 'smooth' });
问题:
- 治标不治本
- 多输入框体验很怪
- 页面高度逻辑本身还是错的
正确解法一:用
svh
,让页面"稳住" 🧘♂️
arduino
.page {
min-height: 100vh;
min-height: 100svh;
}
为什么
svh
有用?
-
svh = 最小视口高度****
-
软键盘弹起时:
-
可视区域只会变小
-
页面不会出现"被盖住却不滚"的情况
-
✅ 不抖
✅ 不需要 JS
✅ 非常适合表单 / 登录 / 支付页
正确解法二:沉浸式场景用
dvh 🎮
css
.page {
height: 100vh;
height: 100dvh;
}
dvh 的特点是:
-
视口变,它就变
-
键盘弹起,页面高度立刻重新计算
适合:
-
活动页
-
视频页
-
对高度变化有心理预期的页面
⚠️ 不太适合关键表单页(容易抖)
那
100%
能不能救?答案是:不能 🙅♂️
css
.page {
height: 100%;
}
原因很简单:
-
100% 依赖父容器高度
-
父容器通常还是 100vh
-
本质问题没有变
一句话点醒自己:
100% 是布局单位,不是视口单位。****
我的最终推荐(直接抄作业 ✍️)
✅ 表单 / 登录 / 支付页
arduino
.page {
min-height: 100vh;
min-height: 100svh;
}
✅ 沉浸式页面
css
.fullscreen {
height: 100vh;
height: 100dvh;
}
写在最后
以前我们总想着:
用 JS 去修补浏览器的坑
但现在发现:
CSS 自己已经进化了,只是我们还在用旧认知。****
如果你也在 Android H5 上被软键盘折磨过,
希望这篇能帮你少掉几根头发 🧠✨