ios 11+ safari/webkit 中 env() 仅支持四个安全区变量:safe-area-inset-top/right/bottom/left,须带 fallback 如 env(safe-area-inset-top, 0),仅限 css 声明使用,不可在 js 或 var() 中调用。

env() 函数在 iOS 中实际能用的四个安全区变量
iOS 11+ 的 env() 函数只在 Safari(及所有基于 WebKit 的 WebView)中支持,且仅暴露四个环境变量:safe-area-inset-top、safe-area-inset-right、safe-area-inset-bottom、safe-area-inset-left。它们不是 CSS 自定义属性,不能用 var(--x) 读取,也不能在 JS 中通过 getComputedStyle 获取 —— 只能在 CSS 声明值里直接使用。
常见错误是写成 padding: env(safe-area-inset-top) 0 却没设 fallback,导致旧版 iOS 或 Android 直接忽略整条声明;更隐蔽的坑是把 env() 当成函数调用,写成 env("safe-area-inset-top")(带引号或括号错误),浏览器会静默失败。
- 必须写成
env(safe-area-inset-top),不加引号、不加括号 - 务必搭配 fallback:例如
padding-top: env(safe-area-inset-top, 0) -
env()的值是长度单位(如44px),可直接参与 calc() 运算 - iOS 15.4+ 开始支持
env(safe-area-inset-*)在非视口元素上生效(如 modal 内部),但 iOS 14 及更早版本只在根元素或position: fixed元素中可靠
适配刘海屏:顶部安全区的正确写法
刘海区域影响的是页面顶部内容(如导航栏),但直接给 <header></header> 加 padding-top: env(safe-area-inset-top) 很容易出问题 —— 如果 header 高度固定(比如 height: 64px),叠加安全区 padding 后可能撑高、错位,甚至触发横向滚动。
更稳妥的做法是用 padding-top + calc() 控制总高度不变:
header {
height: 64px;
padding-top: env(safe-area-inset-top, 0);
padding-bottom: calc(64px - 44px - env(safe-area-inset-top, 0));
}
但注意:这个写法依赖你已知「设计稿基准高度」(如 44px 是常规状态栏高度)。更通用的解法是放弃固定 height,改用 min-height 和 flex 布局对齐内容。
- 避免对
body或html设置padding-top,会导致整个页面下移,影响锚点定位 - 如果用
position: sticky导航栏,需额外加top: env(safe-area-inset-top),否则会卡进刘海区 - 微信内置浏览器(WKWebView)在 iOS 16.4+ 才完整支持
env(),低版本返回0,fallback 必须真实可用
处理底部小黑条:inset-bottom 不等于“留白”
env(safe-area-inset-bottom) 返回的是底部安全区高度(iPhone X~14 系列约 34px,iPhone 15 Pro 约 49px),但它**不是**你需要“避开”的绝对距离 —— 尤其当页面有 overflow-y: scroll 时,小黑条只遮挡 viewport 底部,不影响滚动内容本身。
典型误用:给 footer 加 margin-bottom: env(safe-area-inset-bottom),结果在无小黑条的设备上多出空白;或者给 body 设 padding-bottom,导致页面底部永远空一块。
- 真正需要 inset-bottom 的场景只有两类:固定定位的底部操作栏(
position: fixed; bottom: 0)、全屏 canvas/webgl 渲染区域 - 对固定底部栏,推荐写法:
padding-bottom: env(safe-area-inset-bottom, 0),而非 margin - 若用
vh做全屏布局(如height: 100vh),必须替换为height: 100dvh(iOS 16.4+)或降级为calc(100vh - env(safe-area-inset-bottom, 0)) - 不要在 JS 中监听
resize去动态修改样式 ——env()值变化时不会触发 resize 事件
兼容性兜底与真机调试关键点
env() 没有渐进增强 API,只能靠 CSS fallback 和设备检测组合防御。最常被忽略的是:Safari 的「显示菜单栏」开关(设置 > Safari > 显示菜单栏)开启后,safe-area-inset-top 会从 44px 变成 88px,而用户根本不会意识到这是你的页面问题。
真机调试时,务必关闭「自动隐藏工具栏」和「放大文本」等辅助功能,否则 env() 返回值会异常;Xcode 模拟器默认不模拟小黑条,得手动打开「Hardware > Device > iPhone with Home Indicator」。
- Android 完全不支持
env(),别指望它 fallback 到env(safe-area-inset-bottom, 0)就能跨平台 - 可以结合
@supports (padding: env(safe-area-inset-top))做特性检测,但注意该语法在 iOS 14.5 之前不被识别 - 线上灰度时建议加埋点:用
getComputedStyle(document.documentElement).getPropertyValue('padding-top')采样实际生效值,比猜更可靠 - 如果你用 Vue/React,别在 style binding 里拼
env()字符串(如:style="{ padding: `env(safe-area-inset-top)` }"),Vue 会转义,应改用 class 控制
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











