971 字
5 分钟
关于 vw、vh 在移动端行为不一致的问题

起因与情况#

昨天遇到了一个 Bug,有小伙伴反馈页面的应用窗口在手机上看不全,我自己拿 iPhone 16 试了一下,没复现,我就以为是一些杂牌浏览器的问题,以前也见过类似的,比如浏览器下方工具栏弹出的时候会遮挡页面。

在和他进行讨论后,发现他不管什么浏览器都会出现这种问题,包括换一台手机也一样,换的也是安卓,我也和他一起换,但我自己手机上还是没问题,后来我找了一台安卓机过来,复现了。

我发两张对比图:

alt text alt text

白色主题的是 iOS 上的浏览器,黑色主题的是安卓上的浏览器,同样的代码,在不同设备上的效果不一样。

复现和分析#

Demo 代码如下:

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;
      height: 100%;
      overflow: hidden;
    }

    .container {
      position: absolute;
      width: 100vw;
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      background: rgba(0, 0, 0, 0.3);
    }

    .card {
      position: relative;
      height: 90%;
      width: 80%;
      background: white;
    }

    .footer {
      position: fixed;
      left: 50%;
      transform: translateX(-50%);
      bottom: 8px;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="card">
      卡片
    </div>
  </div>
  <div class="footer">123123</div>
</body>
</html>

简述一下最小的复现场景,外层容器设置了position 和 100vw、100vh 的尺寸,内容高度是百分比,也就像相对于容器的。

按理说容器全屏,内容高度百分比,是绝对不会超出 viewport 的大小的,即便是浏览器上下工具栏对 viewport 有挤压,也只是会影响 viewport 的高度。

为了避免工具栏漂浮,覆盖了部分页面,我加了一个 footer 作为 fixed 固定在浏览器窗口下方,可以看到 123123 是没有被遮盖的,也就是说此时浏览器窗口并没有被下方工具栏漂浮遮挡

所以我这里就觉得是 container 的问题了,后面排除了一下,确定问题出在 vw、vh 单位上,查了一下原因,也和读者分享一下。

vw、vh 单位,确实能表示 viewport 的尺寸,但是问题出在他们是静态的单位,他们在确定了具体的尺寸(px)之后就不会改变了,什么情况下会造成改变呢?比如工具栏,如果出现了工具栏,那么很明显用户能看到的部分变小了,但是 vh 并不会改变,可视区域小了,但尺寸不变,那肯定有一部分不可见了。

alt text

这一张来自 StackOverflow 的图就能很好的说明问题,viewport 高度始终是 100vh,但用户能看到的部分不等于 viewport。

还记得开头说的吗,iOS 上无法复现,对的,iOS 的 WebKit 和 安卓的 WebView 实现不一样,iOS 上用的是动态 vw、vh,也就是 viewport 的实际尺寸会根据可见区域进行调整,出现工具栏了,那么 100vh 对应的 px 就会减少,用户看到的可视区域就是 viewport。

解决#

知道了原因,解决方案就出来了,有几种。

第一是自己维护一个变量作为 vw、vh 对应的像素数,通过 window 的 innerWidth 和 innerHeight 计算,再加上一个 resize 事件重算。

第二是用新单位 dvw 和 dvh,表示动态的 viewport 尺寸,22 年实装的,但肯定有不少用户懒得更新浏览器。

第三是避免这个单位,比如刚刚 Demo,完全可以用百分比来确定容器的尺寸。

关于 vw、vh 在移动端行为不一致的问题
https://blog.erio.work/posts/关于vwvh在移动端行为不一致的问题/
作者
Dupfioire
发布于
2025-04-25
许可协议
CC BY-NC-SA 4.0