position: fixed 底部导航遮内容是因脱离文档流,主内容从视口底端绘制;需用 margin-bottom: calc(var(--nav-height) + env(safe-area-inset-bottom)) 预留空间,并配 viewport-fit=cover,禁在导航内放输入框。

position: fixed 能实现底部导航栏“始终可见”,但直接写 bottom: 0 必然遮内容、点不到按钮、软键盘弹出后错位——这不是 bug,是 CSS 规范行为:fixed 元素完全脱离文档流,浏览器渲染主内容时根本“看不见”它。
为什么 fixed 底部导航总盖住内容?
因为 position: fixed 让元素不参与布局计算,也不占空间。主内容从视口底部开始绘制,自然长进导航栏下面。你看到的“被遮住”,其实是内容真的在导航层下方,而非视觉重叠。
- 不是样式没生效,是布局逻辑本就如此
-
z-index再高也救不了点击失灵——按钮在视觉层下面,但事件捕获仍发生在它原本的位置(已被导航覆盖) - 安卓旧 WebView、微信某些版本还会把
fixed退化成static,连固定效果都失效
必须配 viewport-fit=cover 才能用 env(safe-area-inset-bottom)
iPhone X 及后续机型底部有约 34px 的手势条区域,env(safe-area-inset-bottom) 是唯一标准方式获取该偏移值,但它默认不生效。
- 缺这句
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">,env(safe-area-inset-bottom)返回0,iOS 导航按钮直接沉进手势条里 - Android 旧系统忽略
env()会 fallback 为 0,无副作用;iOS 返回真实值(如34px),无需 JS 判断 - 不要混用
constant(safe-area-inset-bottom)(已废弃),Safari 16.4+ 已不支持
给 <main> 加 margin-bottom,别碰 <body> 的 padding-bottom
预留底部空间必须作用在主内容容器上,且优先选 margin-bottom。
立即学习“前端免费学习笔记(深入)”;
-
<body>设padding-bottom会改变document.body.scrollHeight,导致IntersectionObserver、滚动监听、第三方弹窗库(如 antd-mobile)判断异常 -
<main>或<div class="page-content">加margin-bottom: calc(60px + env(safe-area-inset-bottom))更干净 - 高度不能硬写
60px:要包含真实导航高度(含padding、border),建议用 CSS 变量统一管理::root { --nav-height: 60px; },再写margin-bottom: calc(var(--nav-height) + env(safe-area-inset-bottom));
z-index 和层叠上下文容易踩的坑
设 z-index: 9999 不仅没必要,还可能压住系统级 UI(如 iOS 分享面板、原生日期选择器)。
- 推荐层级:导航栏
z-index: 100,弹窗类组件z-index: 1000,中间留缓冲区 - 检查导航栏父容器是否用了
transform、filter或will-change——这些会隐式创建新层叠上下文,导致子元素z-index失效 - 真机调试时,在 Safari 开发者工具里看 computed 样式,确认
position仍是fixed,没退化成static
最易被忽略的是软键盘弹出时的错位:iOS Safari 对 position: fixed 的重排支持不完整,键盘收起后导航栏坐标卡在旧位置。解决办法不是调 top 或 bottom,而是确保所有可聚焦元素调用 scrollIntoView({ behavior: 'smooth', block: 'nearest' }),并绝对不在导航栏内部放 <input> 或 <textarea>。


















