应使用@supports(min-height:100dvh)包裹min-h-[100dvh]并删除height=device-height、添加viewport-fit=cover,否则iPhone因地址栏收放导致100vh不更新而留白。

直接用 min-h-[100dvh] 替换 min-h-screen,但必须配 @supports 降级、删掉 height=device-height、加 viewport-fit=cover —— 缺一不可,否则白边照旧。
为什么 iPhone 上 100vh 会留白
iOS Safari 把地址栏高度算进 100vh 的基准(比如物理屏高 812px),但滚动后地址栏收起,可视区域变大,100vh 却不更新,导致容器“矮了一截”,底部露出背景色或父容器底色。这不是 Tailwind 写错了,是浏览器单位逻辑本身有缺陷。
-
min-h-screen编译为min-height: 100vh,和手写 CSS 一样失效 - 软键盘弹出时同理:视口动态收缩,
vh值冻结不动 - 部分安卓 WebView(如华为 EMUI)甚至完全忽略
vh,直接回退为auto
必须用 @supports(min-height: 100dvh) 包整条规则
裸写 min-h-[100dvh] 或只在 class 里覆盖值,iOS 15.x 和微信 WebView 会直接跳过该声明,元素高度变成 auto,页面视觉上“塌成一条线”。
- 错误写法:
min-h-screen min-h-[100dvh]→ 老 Safari 忽略第二项,新 Safari 仍走100vh - 正确结构:先兜底
min-h-screen,再用@supports块整体替换 - Tailwind 需 ≥ 3.3 才支持
100dvh;低于此版本需手动扩展或 JS 回退
.page {
min-height: 100vh;
}
@supports (min-height: 100dvh) {
.page {
min-height: 100dvh;
}
}
viewport-fit=cover 和 safe-area-inset-bottom 缺一不可
没加 viewport-fit=cover,env(safe-area-inset-bottom) 永远返回 0px,iPhone 底部按钮/导航栏就会被圆角或 Home Indicator 遮住,形成“假白边”。
立即学习“前端免费学习笔记(深入)”;
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">必须出现在<head>,且不能被构建工具删掉 - 安全区 padding 要加在内容容器上(如
<main class="pb-safe">),不是body或fixed元素 - Tailwind 默认无
pb-safe,需在tailwind.config.js中扩展:paddingBottom: ['env(safe-area-inset-bottom)', 'constant(safe-area-inset-bottom)'] - 旧版 iOS(11.0–11.2)只认
constant(),顺序必须是constant()在前、env()在后
容易被忽略的 Flex 布局断链点
哪怕用了 100dvh + @supports,只要中间某层容器漏了 flex-1 或 h-full,高度链就断了,主内容区塌缩,footer 被挤到视口外,形成“不可见白边”。
-
html或body加了h-full,但外层 wrapper(如<div id="app">)没设h-full或flex-1→ 断链 - 侧边栏用
fixed但父容器仍占文档流位置,间接撑高body,触发垂直滚动条,破坏 flex 高度计算 - 多个输入框共用底部栏时,仅监听单个
focus不够,要用document.activeElement统一判断焦点状态 - 删掉
<meta>中的height=device-height—— 这个参数会让所有vh类失效
最麻烦的不是单位选错,而是降级链断裂:@supports 没包全、viewport-fit 缺失、flex 链中间漏一个 flex-1、JS 初始化时机不对——任一环节出问题,白边就回来。


















