必须加 table-layout: fixed 才能真正固定首列,否则所有宽度设置均为建议值;需配合明确的 table 宽度(如 width: 100%)和正确位置的 <colgroup><col style="width: 120px"><col><col></colgroup>(位于 <thead> 前、<table> 直接子元素),并处理内容溢出与 sticky 固定效果。

必须加 table-layout: fixed 才能真正固定首列
不设这个,所有“固定宽度”操作都只是建议值,浏览器会根据内容(比如无空格 URL 或长中文词)反复重算列宽,<col>、td:first-child、甚至 width 属性都会被忽略。
它不是可选项,而是整个机制的开关。设了之后,浏览器才只看第一行或 <col> 的声明来分配空间,后续行的内容再长也不会撑开列。
-
table必须有明确的width(如width: 100%或width: 800px),否则table-layout: fixed下列宽百分比无参照,像素值也可能坍缩 - 仅靠
td:first-child { width: 120px }不可靠:它只影响渲染时的初始计算,在fixed模式下不会被采纳;在auto模式下又容易被第二行同列内容覆盖 - 如果你用的是 flex 容器包裹表格,记得给该容器加
min-width: 0,否则 flex 会阻止子元素收缩,导致列宽失控
<colgroup> 的位置和写法不能错
<colgroup> 必须是 <table> 的**直接子元素**,且必须出现在 <thead> 或第一行 <tr> 之前。写进 <thead> 里、或者放在 <tbody> 后面,等于没写。
每一列对应一个 <col>,顺序不能乱。想固定第一列、其余列自适应,就这么写:
立即学习“前端免费学习笔记(深入)”;
<table style="width: 100%; table-layout: fixed;">
<colgroup>
<col style="width: 120px">
<col>
<col>
</colgroup>
<thead><tr><th>ID</th><th>Name</th><th>Email</th></tr></thead>
<tbody><tr><td>1</td><td>Alice</td><td>a@example.com</td></tr></tbody>
</table>
- 第二、三列的
<col>可以留空,浏览器会把剩余宽度均分;也可以显式写style="width: auto",但没必要 - 不要混用:
<col>设了宽度,就别再给th或td加width,否则可能冲突 - 如果表格列数动态变化,
<colgroup>也得同步生成——服务端渲染或 JS 插入时容易漏掉这步
首列固定后内容溢出怎么处理
<col style="width: 120px"> 只是划了地盘,不处理内容就会换行失真、或直接撑破列宽。尤其遇到长 URL、无空格英文、或未限制尺寸的图片。
统一加在 td, th 上最稳妥:
td, th {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
- 避免用
word-break: break-all:中文会在字中间硬切,阅读体验差 - 对含 URL 或英文的列,优先用
overflow-wrap: break-word,它会在单词内合理换行 - 如果首列要放图片,记得额外加
img { max-width: 100%; height: auto; },否则图片会无视列宽
滚动时让首列“粘住”需要额外 CSS
上面说的只是列宽固定,不是视觉上“随滚动一直留在左边”。要实现 sticky 效果,得叠加 position: sticky。
关键点有三个:
- 外层容器必须设
overflow: auto(或scroll),且高度/宽度受限,否则sticky不触发 -
td:first-child, th:first-child都要加position: sticky; left: 0; z-index: 10;只设th会导致 tbody 行滚动时首列消失 - 表头首列要更高
z-index(比如z-index: 20),否则会被普通行的首列盖住
最容易被忽略的是:如果父容器用了 overflow: hidden,sticky 会完全失效——它依赖父级滚动上下文,而 hidden 切断了这个上下文。



















