真正可用的是 env(safe-area-inset-*) 环境变量,需同时满足 viewport-fit=cover、@supports(padding-top:env(safe-area-inset-top)) 检测、合理 fallback 三者;android chrome 不支持,ios 仅在视口变化时更新值,软键盘弹出不触发更新。

没有叫 safe-area-inset 的 CSS 属性,真正可用的是 env(safe-area-inset-top) 这类环境变量,且必须同时满足 viewport-fit=cover、@supports 检测、合理 fallback 三者,缺一不可。
viewport-fit=cover 是前提,不加就全为 0px
iOS 只在明确启用视口扩展时才注入 safe-area-inset-* 值。没这句 meta,env(safe-area-inset-bottom) 就算写十遍也返回 0px:
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">必须存在,且不能被 JS 或第三方库覆盖 - 部分 PWA 或全屏模式下,
viewport-fit=cover还会影响 Safari 地址栏是否自动隐藏——这会动态改变env(safe-area-inset-top)的值 - Android Chrome(非 WebView)即使加了该 meta,
env()依然不识别;Pixel、旧版三星等设备别指望它生效
@supports 必须写对语法,否则整块规则被忽略
写成 @supports (env(safe-area-inset-top)) 是非法语法,浏览器直接跳过整个 @supports 块。正确写法是把 env() 放进属性声明里:
- ✅ 正确:
@supports (padding-top: env(safe-area-inset-top)) { ... } - ❌ 错误:
@supports (env(safe-area-inset-top)) { ... } - fallback 值建议设为保守估计(如
44px或20px),别用0px——否则老设备上导航栏可能紧贴状态栏被裁切 - 不要在同一个选择器里混写
constant()和env():Safari 15+ 已彻底移除constant(),留着只会增加维护成本
fixed 元素被遮挡?padding 不起作用,得改定位
padding-bottom: env(safe-area-inset-bottom) 对 position: fixed; bottom: 0 的 tabbar 完全无效——因为 fixed 元素脱离文档流,padding 是内部空间。
- 正确做法是控制定位偏移:
bottom: env(safe-area-inset-bottom, 0px)(注意单位不能省) - 更现代的写法是用
inset:inset: auto 0 env(safe-area-inset-bottom) 0 - 如果用了
z-index分层,确保该元素层级高于系统 UI(如 Safari 地址栏),否则仍可能被盖住 - 别在
height: 100vh容器内叠加padding-bottom:100vh本身已包含手势条区域高度,再加 padding 会造成双倍留白
env() 值不会随软键盘弹出自动更新
iOS 的 env(safe-area-inset-top) 和 env(safe-area-inset-bottom) 只在视口尺寸变化(如旋转)时触发更新。软键盘弹出时视口高度缩了,但 env() 还维持原值——结果就是底部按钮被顶到屏幕中央,留白过大。
- 目前无纯 CSS 方案响应软键盘事件;需结合 JS 监听
resize或focusin手动调整 - React/Vue 的
style={{ paddingTop: 'env(safe-area-inset-top)' }}写法无效——JS 不解析 CSS 函数,只当字符串透传,浏览器收不到 - 横屏、折叠屏、第三方壳等场景下,这些值可能动态变化,不能当静态常量记死
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











