我验了 7 种 sticky 失效说法:3 种根本不成立

给后台加了个吸顶侧栏,本地好好的,一到测试环境就不粘。打开控制台:没有报错,没有警告,position: sticky; top: 0 白纸黑字写在那。我改半小时,改成 relative 又改回来,开始怀疑浏览器。

后来不修了,改搜教程。搜出一堆「sticky 失效的 N 种原因」,说法五花八门还互相打架------有人赖 transform,有人赖 border-collapse,有人直接把 overflow 全家判了死刑。行,那我一个一个验。

判据跑前定死:滚动 250px 后,元素到滚动容器可视顶的偏移,钉在阈值 ±3px 内算粘住,Chrome 实测。先看判决:

网传说法 判定 实测真相
祖先 overflow: hidden,sticky 失效 真死 hidden 劫持了滚动参照系
滚动容器和内容等高,失效 真死 没有滚动空间
sticky 是 flex 子项会失效 真死 stretch 拉满,无处可动
不写 top 不粘 真死 没阈值=普通定位
border-collapse 表头失效 只对一半 几何粘得住,死的是边框
祖先 overflow: clip 也失效 不成立 clip 是解药
祖先 transform 失效 不成立 它只劫持 fixed

7 条说法:3 条不成立,1 条只对一半,4 条真死。而且真死的 4 种控制台全程安静------sticky 这东西,疼了都不喊一声。下面按坑度排。

头号凶手:爷爷辈的 overflow: hidden

最经典的现场:页面滚动好好的,sticky 的某个祖先------轮播外壳、弹窗遮罩、日历浮层------写了 overflow: hidden,吸顶当场失灵。

机制一句话:hidden 也是一个滚动容器,只是你滚不动它。sticky 认滚动祖先只认「最近的」那个,一睁眼把 hidden 层认了------爹自己不滚,它就永远跟着内容走。实测滚动 250px 后,偏移从 126px 变成 -124px,跟得严丝合缝。

sticky 没坏,是被抱错了房间:一心想钉在窗户上,结果被关进一个不动的屋子。

哪里会藏一个 hidden?轮播组件、Modal 遮罩、日历浮层、UI 库的容器组件------好多自带 hidden 裁圆角。sticky 本体没事,是头顶上某个看不见的祖先替它做了决定。

修复两选一:hidden 只是为了裁剪的,换 overflow: clip,后面有对照实验;必须保留 hidden 的,把 sticky 挪出这个祖先,别跟它做亲戚。

死法二和三,其实是同一把锁

等高容器。 sticky 只能在父块范围内活动,父块要是和滚动空间一样高------实测 maxScroll = 0,连滚都滚不起来,粘什么粘。

flex 子项被 stretch。 这个更阴:侧栏自己就是 flex 子项,align-items 默认 stretch 把它拉成和主列一样高。约束块多高它就多高,活动空间归零。实测偏移 2px → -248px,直接滚没影。

html 复制代码
<div style="display: flex;">
  <div style="flex: 1; height: 800px;">主列</div>
  <div style="position: sticky; top: 0;">侧栏</div>  <!-- 被 stretch 拉成 800px -->
</div>

修复就一行:align-self: flex-start,让它塌回自己的高度。实测偏移立刻钉在 2px。中后台侧边栏最常踩这个------左长右短是标配布局。

两件事一个本质:父块和滚动空间一样高,sticky 就没有相对移动的余地。你没想到锁它,flex 替你锁了。

忘写 top:就少一个单词

position: sticky 不带 top(或任意阈值),浏览器当它是 relative。语法合法,控制台安静,就是不粘。排查一晚上,答案是少写一个单词,气人程度五颗星。

css 复制代码
.sidebar { position: sticky; }        /* 等于没写 */
.sidebar { position: sticky; top: 0 } /* 阈值是开关 */

规范原文就这么定的:没有阈值,「钉在哪」就没有定义,退回普通定位。不算坑,算语义------但你得知道。

表格表头:网上说它死,它其实活着

这条先纠错。大量文章说「border-collapse: collapse 会让 th 的 sticky 失效」------实测它粘得住。对照实验 collapse 和 separate 两个表格,th 滚动后偏移都稳稳钉在 2px,几何上没有任何区别。

真正死的是边框。collapse 模式下边框归表格不归单元格:th 被钉在顶上,下边框却跟着表格滚走了,表头和第一行粘成一片。功能活着,视觉死了。这是 Chromium 的已知问题(issue 329702833),Firefox 有同款记录(bugzilla 1727594)。

修复:border-collapse: separate; border-spacing: 0,边框还给单元格。

数据表格是 sticky 的最大用武之地。后台、报表、对账单,都该自查一遍:表头吸住了,第一行的边框还在吗?

两起冤案,当场释放

「祖先有 transform,sticky 就失效。」 前半句对,后半句错。transform 劫持的是 fixed 的参照系,sticky 认的是滚动祖先,管不着。实测祖先挂 translateZ(0),sticky 纹丝不动。这条我跑前就放话:真失效我就弃题不写。结果它粘住了。顺带 will-change: transform 也一样没事。

「overflow 家族都危险。」 恰恰相反,clip 是解药。同样的结构,祖先从 hidden 换成 clip,sticky 吸得死死的------clip 是纯裁剪,不创建滚动容器,sticky 直接跳过它找下一层。2022 年起浏览器支持全绿。修复口诀记这条:裁剪用 clip,别用 hidden。又避坑又救命,全文最值得带走的就是它。

有人会说

「我项目里全是 hidden,sticky 好好的。」------你的 sticky 和 hidden 之间隔了真正的滚动层,它认的是外层,hidden 无罪。但这雷一直在:哪天调整 DOM 把中间那层拆了,hidden 当场顶上。

「不修 sticky,JS 监听 scroll 加 fixed 行不行?」------能跑。代价自己扛:scroll 高频触发要节流、fixed 脱离文档流要补占位、滚动嵌套要重算参照系。三行 CSS 能解决的事,别上 30 行 JS。

「Safari 呢?」------本次是 Chrome 单浏览器几何判据,Safari 未测。表格边框那条 Firefox 有官方记录,其余欢迎 Safari 用户评论区补充实测,先谢过。

速查表,直接存

症状 先查 修复
完全不粘 祖先链有无 hidden/auto/scroll 换 clip,或挪出去
完全不粘 是不是 flex/grid 子项 align-self: flex-start
完全不粘 写没写 top 补阈值
粘了被滚走 父块是不是和内容等高 拉开高度差
吸了没边框 是不是 border-collapse: collapse 换 separate

DevTools 三步收尾:Elements 面板从 sticky 往上爬,遇到第一个 overflow 非 visible 的节点,就是它认的滚动爹;对比这个爹的内容高度和 sticky 父块的高度,一样高就是等高死法;Computed 看 top,空的补上。

最后统计一下:你们项目里现在还躺着几个没写 top 的 sticky?评论区举个手。踩过第 5 种之外死法的更好,留下复现步骤,攒够了我开续集收编。


相关推荐
程序边界1 小时前
一台数据集成软件的拆解笔记(下):一致性、容错、跑批与迁移,KFS 真正难的地方在这
java·前端·笔记
健康活着就好2 小时前
# 前端图片优化实战,首屏加载提速60%
前端
不一样的少年_2 小时前
不花一分额外 API 钱,用现成的 Claude Code / Codex / Cursor 搭建 AI 个人知识库
前端·后端·ai编程
tryCbest2 小时前
ES6 ( ECMAScript 2015)核心语法
前端·ecmascript·es6
李小轰_Rex3 小时前
零开销 AI 数字人方案|Live2D 数字人驱动方案分享
前端·aigc
ModyQyW3 小时前
vite-plugin-uni-manifest 0.7:在 uni-app 读取之前生成
前端·uni-app
我命由我123453 小时前
Python 实用操作 - 文件操作(打开与关闭文件、读取文件、文件写入)
java·开发语言·前端·javascript·数据库·python·java-ee
修炼的dance3 小时前
批量转码前用 ffprobe 筛一遍,36 个文件能跳过 26 个
前端
费曼学习法3 小时前
从 0 到 1 上手 Super-Agent 架构:任务拆解、工具路由与失败回滚的三段实现
前端