用 sticky + top-0 就够了,但父容器不能有 transform、perspective、filter 等会创建堆叠上下文的属性,否则 position: sticky 失效;常见于动画库、backdrop-blur、modal 组件或 group-hover 中意外触发。

直接说结论:用 sticky + top-0 就够了,但必须确保父容器不产生 transform、perspective 或 filter,否则 position: sticky 会失效。
为什么加了 sticky 和 top-0 却不吸顶?
这是最常踩的坑。CSS 的 position: sticky 不是无条件生效的——它会被「最近的具有堆叠上下文(stacking context)的祖先元素」截断。而 transform、filter、perspective、will-change 等属性会隐式创建堆叠上下文。
常见触发场景:
- 父级用了
transform: translateX(0)(比如某些动画库或 UI 框架默认加的) - 外层包裹了
backdrop-blur(它依赖filter) - 导航栏放在
modal或drawer组件里,而该组件内部有transform - 使用了
group-hover并配合transform动画,意外影响了父链
基础写法:一行类名就能跑起来
只要 DOM 结构干净,下面这行就足够让导航栏吸顶:
立即学习“前端免费学习笔记(深入)”;
<nav class="sticky top-0 z-50 bg-white shadow-sm"> <div class="container mx-auto px-4 py-2">Logo & Links</div> </nav>
关键点:
-
sticky是 Tailwind 对position: sticky的封装,不是自定义类 -
top-0控制吸顶后距离视口顶部的距离(可换成top-4留白) -
z-50防止被后续内容遮盖;数值按需调整,不一定要50 - 不需要额外 JS,也不用监听 scroll
需要动态切换样式?别用 scroll 监听,用 data-scroll + group
想实现「滚动后背景变深、文字变小」这类效果,纯 CSS 更轻量。Tailwind 本身不提供 scroll 状态钩子,但可以结合简单 JS 打标记:
<body class="scroll-smooth">
<nav class="sticky top-0 z-50 transition-all duration-300 group"
data-scroll-target>
<div class="container mx-auto px-4 py-3 group-data-[scroll='true']:py-2
group-data-[scroll='true']:bg-gray-900">
<h1 class="text-lg group-data-[scroll='true']:text-base">Site</h1>
</div>
</nav>
</body>
再加一行 JS(仅需一次):
const nav = document.querySelector('[data-scroll-target]');
window.addEventListener('scroll', () => {
nav.dataset.scroll = window.scrollY > 10 ? 'true' : 'false';
});
这样避免了频繁操作 class,也绕开了 IntersectionObserver 的复杂度。
真正难的不是写对类名,而是排查哪个看不见的 transform 把 sticky 给废了。建议用浏览器开发者工具的「Computed」面板,逐级检查 position 是否被降级为 static,再往上翻看 transform 和 filter 的来源。


















