你肯定有遇到过这种情况:费尽心血写了个页面,容器设置了height: 100vh
,在电脑上看完美无缺,结果到手机上......底部居然被浏览器地址栏或者工具栏给挡掉了!
例子 电脑浏览器
手机浏览器

可以看到顶部被浏览器工具栏给遮挡住了。
当你滚动页面时,浏览器地址栏和底部工具栏会自动隐藏/显示。但100vh
取的是包含隐藏地址栏的完整视口高度,而不是当前可见部分的高度。
结果就是:设置了100vh
的元素,实际高度会超出屏幕可见区域,底部内容直接被截断。
实例
来看个真实例子。假设你要做个登录页:
html
<div class="login-page">
<div class="login-form">
<h2>欢迎登录</h2>
<input type="text" placeholder="用户名">
<input type="password" placeholder="密码">
<button>登录</button>
</div>
</div>
css
.login-page {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
电脑上看没问题,但到手机上:
- 页面打开时,地址栏可见,登录按钮可能被推到可视区域外
- 滚动一下,地址栏隐藏了,页面又突然"跳"一下
- 用户体验极其糟糕
用户输完密码找不到登录按钮!
解决方案1:dvh(推荐)
css
.login-page {
height: 100dvh; /* 把vh换成dvh就行 */
}
dvh
是CSS新规范,专门解决这个问题的。它会自动根据浏览器界面变化动态调整高度。
现代浏览器基本都支持了。如果担心老设备,可以加个回退:
css
.login-page {
height: 100vh;
height: 100dvh; /* 优先使用dvh */
}
解决方案2:JavaScript动态计算(备用方案)
如果还需要支持很老的浏览器,可以用JS:
javascript
function setRealVH() {
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--real-vh', `${vh}px`);
}
// 初始化
setRealVH();
// 窗口变化时重新计算
window.addEventListener('resize', setRealVH);
window.addEventListener('orientationchange', setRealVH);
CSS中这样用:
css
.login-page {
height: calc(var(--real-vh, 1vh) * 100);
}
解决方案3:纯CSS Hack(不推荐但可用)
css
.login-page {
height: 100vh;
height: -webkit-fill-available; /* 针对WebKit浏览器 */
}
@media (orientation: portrait) {
.login-page {
height: 100vh;
height: -webkit-fill-available;
}
}
这个方案兼容性一般,但知道一下也没坏处。
建议
- 新项目直接用
dvh
,简单有效 - 老项目逐步替换,先从关键页面开始
- 重要内容永远不要依赖视口底部,确保即使有遮挡也能滚动看到
总结
移动端100vh
的坑确实烦人,但现在有了dvh
这个终极解决方案,问题基本解决了。
下次再做全屏布局,记得用100dvh
而不是100vh
,保你平安无忧。
如果这篇文章帮你省了几个小时的调试时间,帮我点个爱心吧~
我是大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!
📌往期精彩
《写给小公司前端的 UI 规范:别让页面丑得自己都看不下去》
《只会写 Mapper 就敢说会 MyBatis?面试官:原理都没懂》