别再用100vh了!移动端视口高度的终极解决方案

1695次阅读 102人点赞 作者: WuBin 发布时间: 2025-07-18 10:45:22
扫码到手机查看

100VH

作为一名前端开发者,我们一定都遇到过这样的需求:实现一个占满整个屏幕的欢迎页、弹窗蒙层或者一个 fixed 定位的底部菜单。

直觉告诉我们,这很简单,给它一个height: 100vh就行了。

.fullscreen-element {
    height: 100vh;
    width: 100%;
    color: #000;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 10em;
    background-color: #fff;
}

在PC端预览,完美!然而,当你在手机上打开时,可能会看到下面这个令人抓狂的场景:明明是100vh,为什么会超出屏幕高度?这个烦人的滚动条到底从何而来?

问题根源:移动端动态变化的“视口”

要理解问题的本质,我们首先要明白vh(Viewport Height) 单位的定义:1vh等于视口高度的 1%。

在PC端,浏览器窗口大小是相对固定的,所以100vh就是浏览器窗口的可见高度,这没有问题。

但在移动端,情况变得复杂了。为了在有限的屏幕空间里提供更好的浏览体验,手机浏览器(尤其是Safari和Chrome)的地址栏和底部工具栏是动态变化的

  • 初始状态:当你刚进入页面时,地址栏和工具栏是完全显示的。
  • 滚动时:当你向下滚动页面,这些UI元素会自动收缩,甚至隐藏,以腾出更多空间展示网页内容。

关键点来了:大多数移动端浏览器将100vh定义为“最大视口高度”,也就是当地址栏和工具栏完全收起时的高度。

这就导致了:

在页面初始加载、地址栏还未收起时,100vh的实际计算高度 > 屏幕当前可见区域的高度。

于是,那个恼人的滚动条就出现了。

“过去式”的解决方案:JavaScript 动态计算

在很长一段时间里,前端开发者们只能求助于 JavaScript 来解决这个问题。思路很简单:通过window.innerHeight获取当前可见视口的高度,然后用它来动态设置元素的height

function setRealVH() {
  const vh = window.innerHeight * 0.01;
  document.documentElement.style.setProperty('--vh', `${vh}px`);
}

// 初始加载时设置
window.addEventListener('load', setRealVH);
// 窗口大小改变或旋转屏幕时重新设置
window.addEventListener('resize', setRealVH);

然后在 CSS 中这样使用:

.fullscreen-element {
  height: calc(var(--vh, 1vh) * 100);
}

这个方案的缺点显而易见:

  • 性能开销:监听resize事件过于频繁,可能会引发性能问题。
  • 逻辑耦合:纯粹的样式问题却需要JS来解决,不够优雅。
  • 时机问题:执行时机需要精确控制,否则可能出现闪烁。

虽然能解决问题,但这绝不是我们想要的“终极方案”。

终极解决方案:CSS动态视口单位

谢天谢地,CSS 工作组听到了我们的呼声!为了解决这个老大难问题,CSS Values and Units Module Level 4 引入了一套全新的动态视口单位。

它们就是我们今天的“主角”:

  • svh(Small Viewport Height):最小视口高度。对应于地址栏和工具栏完全展开时的可见高度。
  • lvh(Large Viewport Height):最大视口高度。对应于地址栏和工具栏完全收起时的高度(这其实就等同于旧的100vh)。
  • dvh(Dynamic Viewport Height):动态视口高度。这是最智能、最实用的单位!它的值会随着浏览器UI元素(地址栏)的出现和消失而动态改变。

所以,我们的终极解决方案就是:

.fullscreen-element {
  height: 100svh; /* 如果你希望高度固定,且永远不被遮挡 */
  /* 或者,也是我最推荐的 */
  height: 100dvh; /* 如果你希望元素能动态地撑满整个可见区域 */
}

使用100dvh,当地址栏收起时,元素高度会平滑地增加以填满屏幕;当地址栏滑出时,元素高度又会平滑地减小。整个过程如丝般顺滑,没有任何滚动条,完美!

浏览器兼容性

你可能会担心兼容性问题。好消息是,从2023年开始,所有主流现代浏览器(Safari, Chrome, Edge, Firefox)都已经支持了这些新的视口单位。

https://caniuse.com/?search=dvh

https://caniuse.com/?search=dvw

告别100vh的时代

动态判断浏览器是否支持 不支持的情况降级呢
.rule { min-height: 100vh; } @supports (min-height: 100dvh) { .rule { min-height: 100dvh; } }

让我们来快速回顾一下:

  1. 问题:在移动端,100vh通常被解析为“最大视口高度”,导致在浏览器UI未收起时内容溢出。
  2. 旧方案:使用 JavaScript 的window.innerHeight动态计算,但有性能和维护问题。
  3. 终极方案:使用CSS新的动态视口单位,尤其是100dvh,它能根据浏览器UI的变化自动调整高度,完美解决问题。

当需要实现移动端全屏布局时,请大胆地告别100vh,拥抱100dvh

相关资料

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:dvhdvw
推荐阅读
  • python基础-操作列表和迭代器

    python基础笔记-操作列表和迭代器的相关方法

    6402次阅读 143人点赞 发布时间: 2024-06-13 13:26:27 立即查看
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    11248次阅读 754人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    15024次阅读 612人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    14400次阅读 1155人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    18052次阅读 1447人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    16228次阅读 1314人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    31788次阅读 2499人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    27906次阅读 2155人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录