viewport-fit=cover仅是安全区适配起点,必须配合env()函数(如env(safe-area-inset-top))设置容器padding,避免作用于html/body,且需兼容constant()、响应横竖屏动态变化,真机测试不可少。

viewport-fit=cover 是安全区适配的起点,不是终点
只加 viewport-fit=cover 会让内容铺满整个屏幕,但顶部刘海、底部 Home Indicator 区域会直接覆盖你的导航栏或按钮——这不是“适配”,是“硬塞”。它只是告诉浏览器“允许内容延伸到安全区外”,真正起作用的是后续的 CSS 安全区注入。
必须配合 env(safe-area-inset-top) 等函数使用,否则 viewport-fit=cover 没实际意义。iOS Safari 11.0+ 支持 env(),Android Chrome 69+ 也已支持,但旧版 WebView(如部分安卓系统内置浏览器)仍可能 fallback 到 constant(),建议双写:
.header {
padding-top: env(safe-area-inset-top, 0px);
padding-top: constant(safe-area-inset-top, 0px);
}
-
env()是标准函数,优先使用;constant()已被废弃,仅作兼容兜底 - 不要用
env()直接设置margin-top—— 它会把元素整体下推,导致布局错位;用padding更稳妥 - 四个 inset 变量:
safe-area-inset-top、safe-area-inset-bottom、safe-area-inset-left、safe-area-inset-right,横屏时 top/bottom 和 left/right 会互换角色
安全区 padding 必须作用于容器,而非全局 html 或 body
很多人把 env(safe-area-inset-top) 加在 <body> 上,结果整个页面被顶出视口,滚动异常。原因在于:body 默认是块级元素且无显式 height,padding 会撑开它的高度,但 viewport 并不自动适应这个变化。
正确做法是将安全区留白施加在具体容器上,比如页头、页脚、全宽卡片等有明确语义和布局边界的元素:
立即学习“前端免费学习笔记(深入)”;
.app-header {
position: sticky;
top: 0;
padding: env(safe-area-inset-top, 0px) 16px 8px;
background: #fff;
}
- 避免对
<html>或<body>设置安全区相关 padding/margin - 如果使用固定定位(
position: fixed),需确保其父容器有明确高度或使用inset替代 top/left - 圆角区域(如 iPhone 四角)无法通过 CSS inset 控制,只能靠设计规避——关键操作按钮别紧贴角落
横竖屏切换时 safe-area-inset 值动态变化,不能依赖 JS 静态计算
有人用 JS 读取 window.innerWidth 和 window.innerHeight 判断方向,再手动加 class 控制 padding,这会出问题:横屏时 safe-area-inset-top 实际变成 safe-area-inset-left(取决于设备握持方向),但 JS 无法感知系统级安全区重映射。
CSS 的 env() 函数是实时响应的,浏览器内核会在方向变化后自动更新值。你只需写一次规则,无需监听 resize 或 orientationchange 事件:
.sidebar {
padding-left: env(safe-area-inset-left, 0px);
padding-right: env(safe-area-inset-right, 0px);
}
- 不要用 JS 获取
safe-area-inset-*—— 没有对应 API,只有 CSS 环境变量可用 - 媒体查询
@media (orientation: landscape)只反映视口宽高比,不反映安全区偏移方向,不能替代env() - 真机测试必须包含横竖屏切换操作,模拟器有时不会触发 inset 更新
第三方 UI 库(如 Vant、NutUI)默认不处理安全区,需手动包裹或重写样式
像 <van-nav-bar> 这类组件内部没声明 env(safe-area-inset-top),即使你给外层加了,组件自身仍会贴顶渲染,被刘海遮挡。这不是 bug,是设计选择——库无法预判你的容器结构。
解决方式只有两种:要么用 style 属性内联注入,要么用 CSS 选择器穿透覆盖:
.van-nav-bar::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: env(safe-area-inset-top, 0px);
background: inherit;
}
- 不要指望 UI 库自动适配,检查其源码是否含
safe-area-inset相关样式 - 使用
::before占位比修改padding-top更可控,避免影响内部子元素布局流 - 若项目用 Vue/React,可在组件根元素上绑定动态 style:
:style="{ paddingTop: `env(safe-area-inset-top, 0px)` }"



















