应使用@supports检测safe-area-inset变量而非device-width/height媒体查询,因后者在iOS15+不可靠且无法识别viewport-fit=cover;固定定位元素需用constant()/env()动态偏移适配刘海和手势条,viewport meta必须包含initial-scale=1.0。

为什么直接用 device-width 和 device-height 媒体查询会失效
媒体查询里写 @media screen and (device-width: 375px) and (device-height: 812px) 看似精准,但实际在 iOS 15+ 和 Safari 16.4+ 中已不可靠。系统会动态调整报告的 device-height(比如横屏时返回不同值),且“灵动岛”机型(iPhone 14 Pro/15 Pro)的物理尺寸与 iPhone X 不同,但安全区域逻辑一致——靠硬编码尺寸兜底,漏掉新机型是大概率事件。
@supports 检测比媒体查询更可靠
真正要判断的是浏览器是否支持安全区域变量,而不是设备型号。媒体查询无法识别“是否启用 viewport-fit=cover”,而 @supports 能直接验证 env(safe-area-inset-top) 是否可用。
- 必须写成
@supports (padding-top: env(safe-area-inset-top))—— 写成@supports (env(safe-area-inset-top))是语法错误,整块规则会被忽略 - 这个检测只在 iOS 11.2+ 生效;iOS 11.0–11.1 只认
constant(),所以仍需降级声明 - Android 厂商几乎不支持该检测,别指望它在小米、OPPO 的 WebView 里返回 true
固定定位元素被刘海遮住,媒体查询解决不了
顶部 position: fixed 导航栏被盖住,不是因为屏幕尺寸不对,而是它紧贴视口顶部(top: 0),而刘海在物理屏幕顶端。媒体查询没法改 top 值,只能靠 CSS 环境变量动态偏移。
- 正确写法是:
top: constant(safe-area-inset-top); top: env(safe-area-inset-top); top: 0; - 顺序不能反:
constant()必须在前,否则 iOS 11.1 下整条规则丢弃,top: 0也失效 - 媒体查询加个
top: 44px硬编码?那在 iPhone 15 Pro 横屏下会错位,在 iPhone 8 上多出空白
底部手势条适配必须用 safe-area-inset-bottom
媒体查询对底部指示条完全无感——它不改变设备分辨率,只影响安全区域高度。用户滑动返回时点不到按钮,根本原因不是“尺寸没匹配”,而是 position: fixed; bottom: 0 把按钮压进了手势条下方。
立即学习“前端免费学习笔记(深入)”;
- 用
padding-bottom: env(safe-area-inset-bottom)对普通容器有效,但对fixed元素无效 - 应改用
inset或bottom:先bottom: constant(safe-area-inset-bottom);,再bottom: env(safe-area-inset-bottom);,最后bottom: 0; - 别在 React/Vue 的
style={{ bottom: 'env(safe-area-inset-bottom)' }}里写——JS 不解析env(),只会当字符串透传
initial-scale=1.0,或被 JS 动态覆盖,导致 env() 始终返回 0px——这时候所有媒体查询和 @supports 都白搭。


















