直接用 padding-bottom: env(safe-area-inset-bottom) 配合 viewport-fit=cover 可解决 iPhone X+ 底部安全区遮挡问题,但必须作用于正确容器、保持 bottom: 0、添加 viewport-fit=cover meta,并提供 CSS 降级(如 padding-bottom: 12px)。

直接用 padding-bottom: env(safe-area-inset-bottom) 配合 viewport-fit=cover 就能解决,但必须加对位置、写对顺序、兜住降级——否则在 iPhone X+ 上导航栏仍会被 Home Indicator 遮住。
为什么 bottom: 0 的 fixed 导航栏会被遮住
iOS 的安全区(尤其是底部约 34px 的 Home Indicator 区域)不参与 CSS 布局计算。position: fixed; bottom: 0 会把元素钉死在视口物理底边,而不是“可用内容区”的底边。结果就是按钮沉进手势条里,点不动、看不见。
这不是样式没生效,是定位基准错了——fixed 只认 viewport 边界,不感知安全区。
- 不能靠
bottom: env(safe-area-inset-bottom)往上提,这只会让导航栏悬空、露出白边 - 不能只加
padding-bottom到导航栏内部,它不影响 fixed 元素的定位框 - 真正要撑开的是导航栏「下方的内容区域」,或「导航栏自身的内容留白」
env(safe-area-inset-bottom) 必须用在 padding/margin 上
这个 CSS 环境变量只能用于 padding-bottom 或 margin-bottom,且必须作用于正确容器:
- 若导航栏是
position: fixed:给它加padding-bottom: env(safe-area-inset-bottom),同时保持bottom: 0 - 若导航栏是 flex 布局的一部分(如
flex-direction: column末尾):给它的父容器(比如main)加padding-bottom: env(safe-area-inset-bottom) - 若导航栏高度固定(如 60px),更稳妥的是:
height: calc(60px + env(safe-area-inset-bottom))+padding-bottom: env(safe-area-inset-bottom),防止内部按钮贴底
别把它塞进 calc() 做乘除运算(如 calc(env(safe-area-inset-bottom) * 2)),Safari 会直接丢弃整条声明。
必须配 viewport-fit=cover,否则 env() 返回 0
env(safe-area-inset-bottom) 不是随时可读的变量——WebKit 只在页面被允许延伸到安全区外时才注入该值。默认的 会把页面“收缩”进安全区内,导致 env() 永远为 0。
- 必须写:
-
viewport-fit=cover单独存在无效,必须和width=device-width、initial-scale=1同时出现 - 微信内置浏览器部分版本(如 8.0.3x–8.0.4x)对
viewport-fit支持不稳定,需 JS 辅助判断是否真有安全区
不加这句 meta,所有 env() 相关样式都形同虚设。
兼容旧 iOS 和安卓:降级必须用 CSS 层叠,不是 JS
env() 在 Android 浏览器、iOS 10 及以下完全不识别,返回 0 或忽略。不能等 JS 检测完再加 class,得靠 CSS 自身 fallback:
- 先写降级值:
padding-bottom: 12px(常见安卓底部导航参考高度) - 再覆盖增强:
padding-bottom: env(safe-area-inset-bottom)—— 后者会自然覆盖前者 - 更严谨可加
@supports (padding-bottom: env(safe-area-inset-bottom))包裹增强样式,但非必需 - 别用
constant(safe-area-inset-bottom):iOS 11.2+ 已废弃,仅老 Safari(11.0–11.1)需要,现在基本可不考虑
最麻烦的不是写法本身,而是微信不同小版本、系统补丁、WebView 内核对 env() 的解析节奏不一致——测的时候好好的,发版后某批用户导航栏忽高忽低,就得靠 JS 注入 class + 手动 fallback 值兜底。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











