用vh+flex是当前最轻量兼容性最好的高度自适应方案,但需viewport-fit=cover和安全区处理;100%依赖父级高度而移动端默认无约束,100vh在iOS可能含地址栏高度,应优先用100svh并渐进增强。

直接说结论:用 vh 控制容器高度 + flex 布局分配内部空间,是当前最轻量、兼容性最好、无需 JS 计算的高度自适应方案;但必须配合 viewport-fit=cover 和安全区处理,否则在 iPhone X 及以上机型顶部会被刘海/状态栏遮挡。
为什么不能只用 height: 100%?
因为 100% 依赖父元素有明确高度,而移动端 HTML/body 默认没有高度约束,链式继承会断在某个父级。常见现象是内容区域“塌陷”,只显示几行文字就到底了,下方大片留白。
-
height: 100vh绕过继承链,直接锚定视口高度,稳定可靠 - 但
100vh在 iOS Safari 中可能包含地址栏高度(尤其滚动后),导致页面被截断;此时应改用100svh(small viewport height)——它排除浏览器 UI 占用,2023 年起已获主流支持 - 安卓部分旧版 WebView 不识别
svh,稳妥做法是回退到100vh,并加@supports (height: 100svh)做渐进增强
flex-direction: column 配合 flex: 1 的实际写法
高度自适应不是“填满整个屏幕”就完事,而是让各区块按逻辑权重自动伸缩。比如头部固定、主体撑满、底部吸底——这正是 Flexbox 的强项。
- 外层容器设
display: flex; flex-direction: column; min-height: 100svh; - 头部(
.header)用flex-shrink: 0防止被压缩,设固定高度或min-height - 主体(
.main)设flex: 1,它会吃掉剩余所有空间 - 底部(
.footer)同样flex-shrink: 0,避免被拉伸变形 - 注意:若主体内还有子 Flex 容器,需显式设
height: 0或min-height: 0,否则flex: 1在嵌套中可能失效
移动端必须处理的安全区与键盘弹起问题
即使高度算准了,iOS 的“安全区”(safe area)和软键盘弹出会直接破坏布局。这不是 CSS 能单独解决的,但可以提前规避。
立即学习“前端免费学习笔记(深入)”;
- HTML 的
<meta name="viewport" content="viewport-fit=cover">是前提,否则env(safe-area-inset-top)无效 - 用
padding-top: env(safe-area-inset-top)保护头部,而不是靠 JS 动态加 class - 当软键盘弹出时,iOS 会缩小视口高度,
100svh自动变小,但flex: 1的主体仍会撑开——这时要在input聚焦时临时给 body 加position: fixed锁定滚动,防止页面上跳 - 避免在
flex: 1区域内放position: absolute元素,它们的定位基准可能因视口变化而偏移
真正容易被忽略的点是:svh 和 lvh 这类新单位在 Safari 16.4+ 才稳定,如果你的项目要兼容 iOS 15 及更早版本,得用 JS 监听 resize 事件 fallback 到 window.innerHeight,且必须防抖——否则快速横竖屏切换会触发上百次重排。


















