配移动端全屏布局配了五年,每次100vh一写上去在手机上就跑出屏幕了——今天三个CSS单位把这个坑彻底填上了

配移动端全屏布局配了五年,每次 100vh 一写上去,在手机上就跑出屏幕了——底部被地址栏截掉一截,滑动的时候整个页面还跳一下。今天 CSS 终于给了三个原生单位,这个坑彻底填上了。

问题出在哪

移动端浏览器有「动态视口」的概念。同一部手机,地址栏展开时可视高度约 716px,折叠后变成 772px,键盘弹起时更小只有 500px 左右。传统 CSS 里写 height: 100vh,浏览器会按最大视口高度算,结果 100vh 实际在 iPhone 上就溢出了 50~80px。

早年大家靠 100% – address_bar_height 硬算,后来用 position: fixed 加各种负 margin hack,再后来用 JS 监听 resize 事件动态设置高度——这些方案都有人用,但每一种都有副作用。

三个新单位对症下药

Chrome/Safari/Firefox 从 2022 年开始陆续支持了三种新的视口高度单位:

dvh(dynamic viewport height)是最常用的那个——它会跟随浏览器 UI 的显隐实时变化,地址栏展开时自动缩小,折叠时自动放大,键盘弹起时也跟着收缩。用 height: 100dvh,固定全屏布局在所有状态下都不会溢出了。

svh(small viewport height)对应的是「浏览器 UI 占据最多空间」的最小视口。如果你要做一个永远贴屏幕底部的导航栏,用 bottom: 0; height: 100svh 可以保证它不会被地址栏或键盘盖掉。

lvh(large viewport height)反过来,是浏览器 UI 完全收起后的最大视口。固定顶栏导航在键盘弹出时不想跟着内容区一起压缩,就用 height: 100lvh 给它一个不动的基准。

实战怎么选

固定全屏容器(移动端 H5 页面最常见)→ height: 100dvh,配合 overflow: auto 让内部内容正常滚动。

固定底部标签栏(TabBar 类)→ position: fixed; bottom: 0; left: 0; right: 0; height: auto; max-height: 100svh,内容多时内部滚动,但不会超出可视范围。

页面顶栏(不希望被键盘挤出视野)→ height: 100lvh,键盘弹起时内容区动,导航栏原地不动。

落地代码

固定全屏容器,最推荐的写法:
.full-screen {
height: 100dvh;
overflow-y: auto;
}

固定底部栏:
.tabbar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: auto;
max-height: 100svh;
}

顶栏不被键盘影响:
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: auto;
max-height: 100lvh;
}

更精细的控制,可以监听键盘事件配合 CSS 变量:
document.addEventListener(“virtualkeyboardshow”, () => document.documentElement.style.setProperty(“–kb-height”, “50vh”));
document.addEventListener(“virtualkeyboardhide”, () => document.documentElement.style.setProperty(“–kb-height”, “0”));

兼容性和坑

所有主流浏览器 2023 年底已全部支持,caniuse 查询结果是 95%+ 覆盖率。旧浏览器降级可以这样写:
.my-container {
height: 100dvh; / 现代浏览器 /
height: 100vh; / 降级备选,实际会溢出但不会坏 /
min-height: -webkit-fill-available; / WebKit 老版补充 /
}

一个容易踩的坑:不要把 100dvh 和 100vh 混用在同一个布局体系里——同一个页面里同时用两种单位,在键盘弹出时会因为基准不一致产生布局撕裂。选一个主单位贯穿全页。

结论

移动端全屏布局不需要 JS,不需要 hack,不需要 Fill-Available 这种私有属性,三个 CSS 单位各司其职就把过去五年的坑平了。现在写移动端 H5,直接 height: 100dvh 就是标准答案。

评论区

0 条评论

登录后可评论。

阿跨·跨端开发 469 阅读