90%的fixed偏移源于viewport标签不全,必须同时设置width=device-width、initial-scale=1.0和maximum-scale=1.0(或user-scalable=no);祖先元素含transform/overflow等会触发stacking context使fixed降级为relative;100vw在iOS含滚动条宽度导致溢出,应改用left-0 right-0。

viewport meta 标签不全导致 fixed 锚点错位
90% 的 position: fixed 偏移不是 CSS 写错了,而是 <meta name="viewport"> 缺关键参数。只写 width=device-width 不够,iOS Safari 和部分安卓 WebView 会因字体小或内容多自动缩放页面,使 fixed 元素的“视口坐标系”和实际渲染视口脱节。
必须同时满足三项:
-
width=device-width:对齐设备逻辑宽度(CSS 像素) -
initial-scale=1.0:禁用初始缩放 -
maximum-scale=1.0或user-scalable=no:防止双指缩放后锚点漂移
完整写法:<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
祖先元素触发 stacking context 或 transform 导致 fixed 降级
iOS Safari 遇到以下任一条件时,会把 position: fixed 降级为 relative 行为,此时 fixed 元素不再相对于视口,而是相对于那个“干扰祖先”:
立即学习“前端免费学习笔记(深入)”;
- 任意祖先设置了
transform(哪怕只是transform: translateZ(0)) - 任意祖先设置了
overflow: hidden或overflow: auto - 任意祖先设置了
filter、perspective或will-change
调试方法:临时给疑似父级加 outline: 1px solid red,观察 fixed 元素是否跟着它移动。修复只有两个选择——删掉无意义的 transform,或用 JS 把 fixed 元素挂到 <body> 直接子级。
100vw 在 iOS Safari 中包含滚动条宽度
用 w-full 或 left-0 right-0 撑满 fixed 导航栏时,右边常溢出——因为 100vw 在 iOS 下等于屏幕物理宽度,含约 15px 滚动条宽度。这不是 bug,是规范行为。
更稳写法:
- 避免
w-full,改用left-0 right-0(等价于width: auto) - 横向居中类(如悬浮按钮)别用
right-0,改用left-1/2 -translate-x-1/2 - 真要撑满且兼容 Safari,可用
w-[100vw]+ml-[-webkit-scrollbar-width](不推荐),或直接上w-[-webkit-fill-available](仅 WebKit 支持)
z-index 层级失效或未声明 stacking context
fixed 元素被遮挡,常因 z-index 生效前提没满足:
-
z-50类只对已定位元素(relative/absolute/fixed)生效 - 父容器没设
relative或显式z-index,子元素的 z-index 就在 body 级别比较,极易被同级遮罩盖住 - Tailwind 默认
zIndex最高只到50,第三方库(如 modal 库)可能设了z-9999,需在tailwind.config.js中扩展theme.extend.zIndex
最易忽略的是:多个 fixed 元素并列时,没设 z-index 就按 HTML 顺序堆叠,后期加新元素容易遮挡错乱。
top-0 left-0 就可能变成“贴着某层 div 的左上角”,而不是你想要的“贴着屏幕左上角”。


















