要让 fixed 元素贴底,只设 bottom: 0 并删除 top 相关声明;用 env(safe-area-inset-bottom) 补齐 iPhone 手势条;主内容区需用 padding-bottom 预留空间;避免在 body 设 padding;iOS 键盘弹出时需禁用导航栏内可聚焦元素并强制滚动对齐。

只设 bottom: 0,别碰 top
同时写 top: 0 和 bottom: 0 是 fixed 元素悬在半空的头号原因。浏览器不会“智能取舍”,而是按声明顺序覆盖,最终可能只剩一个方向生效,或触发高度挤压逻辑(需配合 height)。要贴底,就只留 bottom: 0,删掉所有 top 相关声明。父容器的 padding 或 margin 对它完全无效——fixed 元素定位参考的是视口,不是父盒。
用 env(safe-area-inset-bottom) 补齐 iPhone 手势条
iOS 的底部安全区不是装饰,是真实不可点击区域。直接 bottom: 0 会让导航栏沉进手势条里,按钮点不中。必须加一层动态兜底:
nav {
position: fixed;
bottom: 0;
width: 100%;
height: 60px; /* 实际内容高度 */
padding-bottom: env(safe-area-inset-bottom);
}注意:<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> 必须存在,否则 env() 不生效;Android 旧版忽略该函数会 fallback 为 0,无副作用。
主内容区必须手动预留空间
fixed 元素脱离文档流,正文最后一段文字默认会长进它下面——这不是 bug,是 CSS 的必然行为。不能靠 margin-bottom,它在 flex/grid 布局中极易被折叠失效。正确做法是给主容器加 padding-bottom:
立即学习“前端免费学习笔记(深入)”;
- 值 = 导航栏真实占用高度(含
border、padding)+env(safe-area-inset-bottom) - 推荐用 CSS 变量联动:
:root { --nav-height: 60px; },然后main { padding-bottom: calc(var(--nav-height) + env(safe-area-inset-bottom)); } - 绝对不要在
body上设padding-bottom——会影响scrollHeight和IntersectionObserver判断
iOS 键盘弹出时 fixed 元素会错位
Safari 对视口变化响应不完整:软键盘弹起后,window.innerHeight 缩小了,但 fixed 元素没重排,视觉上“上浮”或“被顶起”。规避手段有限:
- 导航栏内部禁止放
<input>或<textarea></textarea>——这是最大诱因 - 所有可聚焦元素加
scrollIntoView({ behavior: 'smooth', block: 'nearest' }),确保聚焦时不被遮挡 - 不依赖
resize事件做动态修正——iOS 触发不稳定,且有延迟
真正难处理的不是“怎么贴底”,而是“贴底之后,系统 UI(地址栏、键盘、手势条)一动,它就失联”。这种错位没有银弹,只能靠限制交互入口 + 强制滚动对齐来兜底。


















