表头冻结需对每个<th>设position: sticky、top: 0和z-index≥10;双冻结要求左上角单元格同时满足top: 0和left: 0,首列所有<th><td>均需left: 0且z-index分层;容器需固定高+overflow-y: auto;table-layout: fixed时须显式设列宽;选中态推荐事件委托至<table>并用outline实现。

表头冻结必须对每个 <th> 单独设置 position: sticky
直接给 <thead> 或 <tr> 加 position: sticky 无效——浏览器只支持对单元格级元素(<th>、<td>)启用 sticky 定位。常见错误是套一层 div 包裹表格再设滚动,结果表头随内容一起滚走。
正确做法是:
-
<th>必须显式设top: 0和z-index(建议 ≥ 10),否则滚动时可能被<tbody>内容盖住 - 包裹表格的容器需有固定高度 +
overflow-y: auto,不能靠父级高度“撑开” - 若用了
table-layout: fixed,所有列宽必须用width或min-width显式声明,否则 sticky 后列宽会塌缩或错位
首列冻结需要同时处理 <th> 和 <td> 的 left: 0
只冻结表头或只冻结首列都不够——Excel 式双冻结要求左上角单元格(如 ID 列的表头)同时满足 top: 0 和 left: 0,而该列所有数据单元格也必须设 left: 0,否则横向滚动时会出现空白或重叠。
关键细节:
立即学习“前端免费学习笔记(深入)”;
- 首列所有
<th>和<td>都要加position: sticky; left: 0,且z-index要高于其他列(比如表头用 20,数据行用 10) - 背景色必须统一覆盖,避免滚动时露出底层内容;
background-clip: padding-box可防止圆角裁切异常 - 不能对整列用
display: block或强行修改<tbody>的 display,会破坏表格语义和单元格对齐
单元格选中态要用事件委托 + 正确 CSS 层级
直接给每个 <td> 绑 click 事件在动态表格里容易漏绑或重复绑定;而且 border-collapse: collapse 下,box-shadow 或 outline 很可能被压住或贴边。
推荐写法:
- 事件委托到
<table>,监听click,用e.target.matches('td, th')过滤目标 - CSS 中
:hover规则写在前,.selected写在后,确保选中态能覆盖悬停态 - 用
outline而非border实现高亮(不占布局空间),并设outline-offset: 2px避免紧贴边框 - 移动端加
touch-action: manipulation减少点击延迟
合并单元格(rowspan/colspan)无需特殊 JS 处理
浏览器原生支持点击合并单元格任意区域命中对应 <td>,e.target 拿到的就是原始那个带 rowspan 或 colspan 的元素,不需要计算行列范围或手动映射坐标。
但要注意:
- 如果想高亮整个合并区域(比如画虚线框围住所有跨占格子),就得手动遍历
rowspan/colspan值并计算实际占据的行列位置——这开销大,一般项目里没必要做 -
<th rowspan="2">的 sticky 行为和普通<td>一致,只要它本身设了position: sticky; top: 0,就能随表头冻结



















