关于移动端100vh的坑和终极解决方案,看这一篇就够了!

你肯定有遇到过这种情况:费尽心血写了个页面,容器设置了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. 页面打开时,地址栏可见,登录按钮可能被推到可视区域外
  2. 滚动一下,地址栏隐藏了,页面又突然"跳"一下
  3. 用户体验极其糟糕

用户输完密码找不到登录按钮!

解决方案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;
  }
}

这个方案兼容性一般,但知道一下也没坏处。

建议

  1. 新项目直接用dvh,简单有效
  2. 老项目逐步替换,先从关键页面开始
  3. 重要内容永远不要依赖视口底部,确保即使有遮挡也能滚动看到

总结

移动端100vh的坑确实烦人,但现在有了dvh这个终极解决方案,问题基本解决了。

下次再做全屏布局,记得用100dvh而不是100vh,保你平安无忧。

如果这篇文章帮你省了几个小时的调试时间,帮我点个爱心吧~

我是大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《写给小公司前端的 UI 规范:别让页面丑得自己都看不下去》

《只会写 Mapper 就敢说会 MyBatis?面试官:原理都没懂》

《别学23种了!Java项目中最常用的6个设计模式,附案例》

《Vue3+TS设计模式:5个真实场景让你代码更优雅》

《别再手写判空了!SpringBoot 自带的 20 个高效工具类》

相关推荐
05Nuyoah1 分钟前
DAY 04 CSS文本,字体属性以及选择器
前端·css
一條狗2 分钟前
学习日报 20250928|React 中实现 “实时检测”:useEffect 依赖项触发机制详解
前端·react.js
Gazer_S4 分钟前
【React 状态管理深度解析:Object.is()、Hook 机制与 Vue 对比实践指南】
前端·react.js·前端框架
Nicholas686 分钟前
flutter视频播放器video_player_avfoundation之AVFoundationVideoPlayer(三)
前端
Asort8 分钟前
JavaScript设计模式(六)——适配器模式 (Adapter)
前端·javascript·设计模式
是晓晓吖12 分钟前
Puppeteer page.on('response',fn)的最佳实践之等待响应
前端·puppeteer
跟橙姐学代码13 分钟前
给Python项目加个“隔离间”,从此告别依赖纠缠!
前端·python·ipython
Cache技术分享18 分钟前
202. Java 异常 - throw 语句的使用
前端·后端
_AaronWong21 分钟前
Electron全局搜索框实战:快捷键调起+实时高亮+多窗口支持
前端·搜索引擎·electron