viewport-fit=cover必须写在meta标签中,否则env(safe-area-inset-bottom)等安全区域变量值为0px;它仅在iOS Safari中生效,需配合@supports检测并提供fallback。

viewport-fit=cover 必须写在 meta 里,缺了它 env() 全是 0px
env(safe-area-inset-bottom) 看起来像普通 CSS 变量,但它根本不是——它是 iOS Safari 的“开关型变量”:只有 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> 完整存在且未被 JS 动态覆盖时,浏览器才注入这些值。漏掉 viewport-fit=cover,或只写 initial-scale=1.0,getComputedStyle(document.body).getPropertyValue('padding-bottom') 就永远返回 0px。
常见错误现象:
- DevTools 模拟 iPhone X/12/14 显示正常,真机上按钮直接被小横条盖住
- 用
console.log(getComputedStyle(document.body).getPropertyValue('--safe-area-inset-bottom'))读出来是空字符串或0px
实操建议:
- 检查 HTML 中是否仅有一个
<meta name="viewport">,且内容含viewport-fit=cover - 避免 JS 动态重写
document.querySelector('meta[name="viewport"]').setAttribute(...),会破坏注入时机 - 微信、飞书等 WebView 不支持
viewport-fit,此时env()直接被忽略,不报错也不生效
padding-bottom: env(safe-area-inset-bottom) 是主流写法,但不能乱套
padding-bottom: env(safe-area-inset-bottom) 适用于容器类元素(比如 <main>、<footer>),让内部内容自然上浮,避开底部 Home Indicator。它改变的是元素自身内边距,不影响布局流。
立即学习“前端免费学习笔记(深入)”;
容易踩的坑:
- 对
position: fixed; bottom: 0的 tabbar 写margin-bottom: env(safe-area-inset-bottom):会导致页面可滚动高度变大,手指一滑按钮就“掉出”视口 - 给普通块级元素写
margin-bottom: env(safe-area-inset-bottom):视觉留白但父容器高度没撑开,可能引发其他元素错位 - 写成
padding-bottom: var(--safe-area-inset-bottom):var()读不到环境变量,必须用env()
正确示例:
body {
padding-bottom: 20px;
}
@supports (padding-bottom: env(safe-area-inset-bottom)) {
body {
padding-bottom: env(safe-area-inset-bottom);
}
}
fixed 底部栏要用 calc() + env(),别直接设 bottom: 0
对于 position: fixed; bottom: 0 的底部操作栏(如支付按钮、tabbar),不能只靠 padding 推内容——它需要整体上移,同时保持离屏幕底边固定距离(比如 8px)。
实操建议:
- 写法必须是
bottom: calc(8px + env(safe-area-inset-bottom)),不能省略单位或括号 - Safari 15.4 之前不支持单位混合运算(如
calc(8px + env(...))),整条声明会被丢弃,所以必须配合@supports检测 - 降级 fallback 要写在前面:
bottom: 8px;→@supports块里再覆盖 - 绝对定位元素优先用
inset或bottom: calc(...),别写bottom: 0后靠margin补偿
示例:
.tabbar {
position: fixed;
bottom: 8px;
}
@supports (bottom: calc(8px + env(safe-area-inset-bottom))) {
.tabbar {
bottom: calc(8px + env(safe-area-inset-bottom));
}
}
@supports 检测比 UA 判断靠谱得多
UA 字符串不可靠:iOS 版本号和 WebView 实现差异太大,微信、钉钉、飞书对 viewport-fit 支持程度不一,JS 判断容易漏判或误判。
唯一推荐的检测方式是:
@supports (padding-bottom: env(safe-area-inset-bottom)) { ... }
注意:
- 不要用
@supports (env(safe-area-inset-bottom)):语法错误,env()必须出现在属性值上下文中 - 旧版 iOS(如 11.2)连
@supports都不支持,所以 fallback 必须写在@supports外层 - 安卓或桌面浏览器不识别
env(),但会忽略该声明,退回到前一条 CSS,这是 CSS 层叠机制本身的设计,无需 polyfill
真正容易被忽略的点是:安全区域变量在非刘海屏设备(如 iPhone 8)上也存在,只是值为 0px,所以 fallback 不影响正常设备;但如果你在 JS 里做逻辑判断,得留意这个“0px”不是“未定义”,而是真实数值。


















