应使用 min-height: 100dvh 替代 height: 100vh,因 ios safari 等浏览器在软键盘弹出时不更新 vh 值,导致内容截断;需配合 max-height: 100dvh、flex 布局与 overflow-y: auto 实现正确响应。

用 min-height: 100dvh 替代 height: 100vh 是基础动作
不是所有浏览器都把软键盘当成“视口变化”,iOS Safari 和多数安卓 WebView(如华为、UC)在键盘弹出时根本不会更新 vh 值,它被锁死在页面加载那一刻。结果就是:容器还按 667px 渲染,但实际可视区只剩 400px,内容被截断、底部按钮悬空。
100dvh 是动态单位,代表“无键盘状态下的完整视口高度”,Chrome 105+、Safari 16.4+ 已稳定支持。但它不能只写 height: 100dvh——必须组合使用:
-
min-height: 100dvh+max-height: 100dvh,否则 flex 子项无法正确分配剩余空间 - 搭配
overflow-y: auto,让内容可滚动而非被压缩 - 所有依赖全屏高度的容器都要改,包括 Tailwind 的
min-h-screen(它编译为min-height: 100vh)
flex 容器必须设 flex-direction: column 并约束子项行为
100dvh 只解决父容器高度问题,子元素仍可能被压缩或错位。关键不在“固定”底部,而在“守住”关键区域的空间。
- 根容器(如
#app或body)要设display: flex; flex-direction: column; min-height: 100dvh - 主内容区加
flex: 1; overflow-y: auto,确保它撑满剩余空间且独立滚动 - 底部固定区域(如输入框、发送按钮)必须加
flex-shrink: 0;光写这个还不够,建议用flex: 0 0 auto更明确 - 删掉
<meta>中的height=device-height——这个参数会让所有vh/dvh单位失效
别用 position: fixed 锚定底部交互元素
软键盘会压缩 visualViewport.height,但 fixed 元素不重算位置,iOS 上常直接飘到屏幕中间,甚至被顶出可视区。这不是 bug,是浏览器行为。
- 把底部按钮放进和输入框同级的
position: relative容器里,用display: flex对齐 - 或者用
margin-top: auto推到底部——前提是父容器是 flex column 且高度可控 - 若必须用 JS 动态调整,优先读
visualViewport?.height,比window.innerHeight准确得多;resize事件在 iOS 键盘收起时才稳定,弹出时基本不触发
viewport 配置和安全区一个都不能少
即使写了 100dvh 和 flex,<meta name="viewport"> 配错也会让一切失效。真机常见现象:页面整体缩小、右侧滑出空白、document.documentElement.clientWidth 远小于屏幕宽度。
-
最前面必须有:<meta name="viewport" content="width=device-width, initial-scale=1.0"> - 禁用
maximum-scale=1或固定width=375——它们会强制缩放,干扰视口单位解析 - 全面屏设备需加
padding-bottom: env(safe-area-inset-bottom),否则底部按钮仍会被手势条遮挡
真正容易被忽略的是:100dvh 在老版本 Safari(如 iOS 16.3 及更早)中会被直接忽略,降级方案必须存在——比如用 focusin 记录基准高度,再结合 setTimeout 读取重排后的 getBoundingClientRect(),而不是等 resize。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











