必须添加 viewport-fit=cover 才能启用 env(safe-area-inset-*),否则恒为 0px;@supports 检测最可靠;padding-bottom 是唯一稳妥的适配方式;calc() 需分层写 fallback;constant() 已废弃。

不加 viewport-fit=cover,env(safe-area-inset-bottom) 永远是 0px —— 这不是 bug,是 WebKit 的硬性前提。
必须写对 viewport meta 才能启用 env() 变量
iOS Safari 只在 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> 完整存在且未被 WebView 覆盖时,才注入 safe-area-inset-* 环境变量。漏掉 viewport-fit=cover,或只写 initial-scale=1,env(safe-area-inset-bottom) 就恒为 0px。
常见陷阱:
- 微信 8.0.22 之前、部分企业微信 WebView、旧版 QQ 浏览器等容器根本不支持
viewport-fit,此时env()直接被忽略 - 某些 Hybrid 容器会强制覆盖
<meta>标签,需用 DevTools 检查渲染后实际生效的content值 -
viewport-fit=auto(默认行为)等价于禁用安全区 API,env()恒为0px
@supports 检测比 UA 判断靠谱得多
UA 字符串不可靠:iOS 版本号和 WebView 实现差异太大,微信、飞书、钉钉等容器对 viewport-fit 支持程度不一,JS 判断容易漏判或误判。
立即学习“前端免费学习笔记(深入)”;
唯一推荐的检测方式是:
@supports (padding-bottom: env(safe-area-inset-bottom)) {
body {
padding-bottom: env(safe-area-inset-bottom);
}
}
注意:@supports 在 iOS 11.2 之前不支持,所以降级必须前置。
padding-bottom 是唯一稳妥的落点方式
对底部 fixed 元素(如 tabbar),直接设 padding-bottom: env(safe-area-inset-bottom) 在该元素自身上;不要写 margin-bottom,它在脱离文档流的元素上不改变布局高度,反而可能撑大可滚动区域。
关键细节:
- 用
margin-bottom会拉高父容器高度,导致手指上滑时按钮“掉进”安全区下方看不见 - flex 布局中靠
margin-top: auto推下来的底部栏,应把padding-bottom: env(safe-area-inset-bottom)加在父容器上 - 顶部
fixed导航栏适配用padding-top: env(safe-area-inset-top),同样不能作用于<body> - 避免对
<body>或<html>直接设padding-bottom,容易引发滚动异常
calc() + fallback 是防失效的底线保障
calc(16px + env(safe-area-inset-bottom)) 在 Safari 15.4 之前不支持单位混合运算,整条声明会被丢弃;但 calc(16px + env(safe-area-inset-bottom, 0px)) 仍不可靠,因 fallback 语法并非全平台支持。
真正稳妥的写法是分层覆盖:
footer {
padding-bottom: 16px;
padding-bottom: calc(16px + env(safe-area-inset-bottom));
}
这样即使 env() 失效,calc(16px + 0px) 仍能算出 16px,保证底线不塌。别再用已废弃的 constant() —— iOS 11.3 起标记废弃,12.0 开始仅保留兼容。
真正容易被忽略的是:安全区域数值是动态的——iPhone 14 Pro Max 的灵动岛在播放音乐、通话时会扩展高度,env(safe-area-inset-top) 会实时变化;但 CSS 无法监听这个变化,JS 也拿不到事件,只能依赖浏览器自动重绘。


















