env()函数在ios 11+中通过safari 11.0注入的四个安全区变量(如env(safe-area-inset-top))实现刘海屏适配,仅限css使用、需viewport-fit=cover启用,并依赖@supports检测与max()兜底确保兼容性。

env() 函数在 iOS 11+ 中读取安全区域的原理
iOS 系统从 Safari 11.0 开始注入四个 env() 环境变量,用于描述刘海屏、Home Indicator 等系统 UI 占用的空间。它们不是 CSS 自定义属性,也不能用 JavaScript 动态读取(getComputedStyle 返回 unset),只能在 CSS 声明中直接使用。
四个关键变量是:env(safe-area-inset-top)、env(safe-area-inset-right)、env(safe-area-inset-bottom)、env(safe-area-inset-left)。它们的值是长度单位(px),仅在真机 Safari 或 WKWebView 中生效;模拟器、Chrome DevTools 模拟 iPhone X+ 时默认为 0px,不可靠。
注意:env() 不支持 fallback 语法(如 env(safe-area-inset-top, 20px) 是非法的),必须配合 calc() 或媒体查询兜底。
用 padding + env() 实现底部操作栏避让 Home Indicator
常见错误是直接给 body 设置 padding-bottom: env(safe-area-inset-bottom),这会导致所有页面底部留白,即使内容没到底部也浪费空间。
更合理的做法是只作用于需要贴底的容器,比如底部导航栏或固定按钮组:
footer {
padding-bottom: env(safe-area-inset-bottom);
/* 必须加这个,否则在非刘海设备上会出错 */
padding-bottom: max(0px, env(safe-area-inset-bottom));
}
max(0px, ...) 是关键兜底——CSS max() 在不支持 env() 的浏览器中会退化为 0px,避免解析失败导致整个声明被丢弃。其他写法如 padding-bottom: env(safe-area-inset-bottom, 0px) 会报 CSS 解析错误。
- 不要在
html或body上全局设置env(),影响不可控 - 若使用
position: fixed; bottom: 0,应改用bottom: env(safe-area-inset-bottom),而非仅靠 padding - Android 设备(包括 Chrome)完全不支持
env(),需依赖@supports (padding-bottom: env(safe-area-inset-bottom))做条件加载
@supports 判断 env() 支持并分层处理
不能靠 UA 判断是否为 iOS,因为 WKWebView、PWA、微信内置浏览器行为不一致;也不能只查 webkit 前缀,iOS 15+ 已移除部分前缀依赖。唯一可靠方式是 CSS 特性检测:
@supports (padding-top: env(safe-area-inset-top)) {
.header {
padding-top: env(safe-area-inset-top);
}
.main {
padding-bottom: env(safe-area-inset-bottom);
}
}
这段代码在 Android Chrome、旧版 Safari、桌面浏览器中会被整块忽略,不会报错也不会影响布局。但要注意:
-
@supports内部不能嵌套媒体查询,想结合横竖屏逻辑得在外面再包一层@media (orientation: portrait) - 某些安卓厂商 WebView(如华为、小米)会错误地声明支持
env(),但返回值恒为0px,建议搭配 JS 检测window.visualViewport?.height与window.screen.height差值做二次校验 - 微信 iOS 客户端 v8.0.23+ 支持
env(),但 v7.x 及更早版本不支持,且无降级提示
viewport meta 标签必须开启 viewport-fit=cover
这是最容易被忽略的前提:如果 <meta name="viewport"> 中没写 viewport-fit=cover,iOS 会强制将页面缩放以避开刘海和 Home Indicator,此时 env() 虽然存在,但值恒为 0px,等于没用。
正确写法是:
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
注意点:
-
viewport-fit=cover仅对 iOS 有效,Android 忽略该参数,无需条件输出 - 加上后,页面会全屏渲染,但内容可能被系统 UI 遮挡——这正是你需要
env()补齐安全边距的原因 - 如果同时用了
maximum-scale=1.0,在 iOS 上可能导致双击缩放失效,部分用户反馈体验下降,按需取舍
没有 viewport-fit=cover,env() 就是空转;写了但没配 @supports 或兜底值,上线就可能白屏或错位。这两步缺一不可,且顺序不能颠倒。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











