直接在 上用 sticky 失效,因 table 默认无滚动上下文;须将 包入 max-h-96 overflow-y-auto 容器, 与之同级,并配合 table-fixed、显式列宽、sticky top-0 z-10 及边框/阴影优化。

为什么直接用 sticky 在 <thead> 上会失效?
<p>因为 Tailwind 的 <code>sticky 工具类依赖父容器有明确的高度限制和 overflow-y 设置,而默认的 <table> 是一个「无约束块级容器」,<code><thead> 和 <code><tbody> 本身不参与 CSS 盒模型的滚动上下文构建。直接给 <code><th> 加 <code>sticky top-0 没用——它没地方“粘”。
真正起作用的是:把 <tbody> 包进一个独立的、带 <code>max-h- 和 overflow-y-auto 的容器,并确保 <thead> 和该容器同级且不被包裹在滚动区域内。
<ul><li>必须将 <code><tbody> 外层套一个 <code><div class="max-h-96 overflow-y-auto">(高度按需调整)
<li><code><thead> 必须和这个 <code><div> 并列,不能被它包裹
<li>给 <code><th> 加 <code>sticky top-0 bg-white z-10,z-10 防止被滚动内容遮挡
table-layout: fixed(Tailwind 对应 table-fixed),否则列宽会因内容撑开,导致表头/表体列不对齐如何保证表头与表体列宽严格对齐?
这是最容易翻车的点。即使用了 table-fixed,如果 <thead> 和 <code><tbody> 的 <code><th>/<code><td> 没有显式宽度控制,浏览器仍可能按各自内容计算列宽,造成错位。
<ul><li>为每列的 <code><th> 设置固定宽度,例如 <code>w-1/5、min-w-[120px] 或 flex basis 配合 table-cell
grid 替代 table:用 <div class="grid grid-cols-[1fr_2fr_1fr]..."> 控制列宽,再分别渲染表头行和滚动行,完全避开 table 渲染逻辑
<li>避免在 <code><th> 中使用 <code>whitespace-normal + 长文本,这会导致换行影响高度,进而让 sticky 行偏移
滚动时表头阴影或边框断裂怎么办?
常见现象是:滚动后,<th> 下方出现一条白边,或阴影只显示半截。这是因为 sticky 元素脱离文档流后,其 box-shadow / border-bottom 默认不延伸到滚动容器边界。
<ul><li>给 <code><th> 显式加 <code>border-b border-gray-200,而不是依赖父 <tr> 的边框
<li>如需阴影,用 <code>shadow-sm + bg-white,并确保 z-10 足够高(z-20 更稳妥)
backdrop-blur 做毛玻璃效果,注意 Safari 对 sticky + backdrop-filter 兼容性差,建议降级为纯色背景移动端适配要注意什么?
小屏幕下固定表头容易挤压内容,或触发横向滚动。不要简单套用桌面端的 max-h-96。
- 用响应式高度:例如
max-h-[calc(100vh-200px)] sm:max-h-96,让大屏有固定高度,小屏占视口大部分 - 列数多时,优先隐藏非关键列(
hidden sm:table-cell),比横向滚动体验更好 - 禁用
user-select: none类样式,否则 iOS 上可能无法拖动滚动条 - 测试真机滚动惯性——某些 Android WebView 对
overflow-y-auto内部的sticky支持不稳定,可加will-change: transform微调
最麻烦的永远不是加几个 class,而是列宽对齐和滚动容器边界控制。哪怕只差 1px,视觉上就是错位。动手前先用 outline 临时标出每个 <th> 和对应 <code><td> 的实际尺寸,比猜强得多。</td>











