position: fixed 本质是相对于视口定位,无法真正实现“在某个 div 内 fixed”;所谓“容器内 fixed”实为因 transform/filter/perspective 等触发 containing block 变更导致的降级行为,应改用 position: relative + absolute 方案。

做不到。 position: fixed 的行为就是相对于视口(viewport),这是 CSS 规范强制定义的,没有合法、稳定、跨浏览器的方式让它“只在某个 div 内 fixed”——这不是限制,是它的本质。
为什么你看到的“fixed 在容器里”其实是错觉
常见错误现象包括:
- 元素写在
<div class="scroll-container"> 里面,但滚动时它悬停在屏幕右上角,不是容器右上角 <li>父容器加了 <code>transform: scale(0.95)或filter: blur(1px),fixed元素突然“掉进”容器里、跟着一起缩放 —— 这不是你想要的“容器内 fixed”,而是fixed降级为absolute,参考系被劫持了 - 用
getBoundingClientRect()测位置,发现top值在滚动时不变,误以为“没生效” -
transform是否为非none(尤其警惕translateZ(0)、scale(1)这类“无感”写法) -
filter是否存在(哪怕只是filter: blur(0)) -
perspective是否被设置 -
opacity是否小于 1 -
will-change是否包含transform或scroll-position - 父容器必须显式设置
position: relative(或absolute/sticky),否则子元素的absolute会一路向上找,最终锚定到 - 父容器要有明确高度或
max-height,且设overflow-y: auto,否则滚动不会触发 - 子元素设
position: absolute,再用top/right/bottom/left定位,比如bottom: 12px; right: 12px
根本原因:只要祖先链上存在 transform(含 translateZ(0))、filter(哪怕 filter: blur(0))、perspective、opacity 或 <code>will-change: transform 等属性,就会创建新的 containing block,fixed 就会失效并降级为相对于该祖先定位。
怎么快速定位是不是 transform 惹的祸
打开浏览器 DevTools,选中那个“不听话”的 fixed 元素,往上看它的所有祖先节点,逐层检查 computed 样式里的以下属性:
一旦发现某层祖先有上述任一属性,基本就是它导致 fixed 降级为 relative-to-parent 定位。
真正该用 position: absolute + position: relative 父容器
这是最轻量、零 JS、兼容性最好的方案,适用于“固定在容器右下角”“悬浮按钮随容器滚动”等典型场景:
注意:absolute 子元素仍属于文档流布局逻辑,不会遮挡其他内容,也不影响父容器高度计算。
真正容易被忽略的是:移动端 iOS Safari 软键盘弹出时,fixed 元素可能贴着键盘顶部而非屏幕顶部;而所谓“修复”手段(如监听 focus 切 absolute)本身就会引入 scroll/resize 监听开销,且在 X5 内核中极易错位。别硬扛 fixed,该换方案就换。











