返回博客

表格列宽莫名膨胀到 150px?罪魁祸首是 input 的隐式 size=20

某天在做一个带筛选行的数据表格,每列表头下面放了一个 <input> 用于本列过滤。布局用 width: max-content 让表格跟着内容自动伸缩,<colgroup> 给固定列指定宽度。看起来很标准,结果上线一跑——每一列都至少 150px,完全无视 colgroup 里写的窄宽,给 input 加 w-full / width: 100% 也没任何效果,把 input 从 DOM 里删掉,列宽瞬间缩回正常。

这个坑卡了我好一阵子,根因相当反直觉。

现象

  • 所有含筛选 <input> 的列,最小宽度强制约 150px,无法更窄
  • <table style="width: max-content"> 本应按内容收缩,但实际宽度远大于文字长度
  • 给 input 加 className="w-full" 毫无改善
  • 删掉 input,列立即变窄,确认 input 是元凶

根因

HTML <input type="text"> 有一个名为 size 的属性,默认值是 20(字符数),对应约 150–180px(取决于字体)。这个值控制的是 input 的内在尺寸(intrinsic size),参与浏览器的 CSS content-box 尺寸计算。

当表格使用 width: max-content 或自动布局时,浏览器会测量每个单元格子元素的内在宽度,取其最大值作为列宽基准。input 那个 20 字符的内在宽度直接把列宽撑到了 ~150px,而且优先级高于外部 CSS

坑:w-full 不会覆盖 input 的内在尺寸

给 input 加 w-full / width: 100% 只会让它在列宽已定之后撑满单元格,但浏览器在计算列宽时用的是 input 的内在宽度——顺序是先量再撑,w-full 对列宽计算毫无影响。

正解

设置 size={1}(或 HTML 里写 size="1"),把 input 的内在宽度压到约 8–10px,使其不再主导列宽计算;再配合 w-full 让 input 跟随列宽拉伸。

修复前(异常)

<th>
  <input
    type="text"
    className="w-full border rounded px-2 py-1"
    value={filter[col.key] ?? ''}
    onChange={e => setFilter(col.key, e.target.value)}
  />
</th>

列宽死锁 ≥150px。

修复后

<th>
  <input
    type="text"
    size={1}
    className="w-full border rounded px-2 py-1"
    value={filter[col.key] ?? ''}
    onChange={e => setFilter(col.key, e.target.value)}
  />
</th>

size={1} 把内在宽度压到接近零,w-full 再把它撑满单元格,列宽完全由 colgroup 或内容驱动。

正解:size={1} + w-full 双管齐下

size={1} 负责消除内在尺寸对列宽的干扰;w-full 负责在列宽确定后让 input 填满单元格。两者缺一不可,顺序不影响,但都得写。

配套:max-content 表格的其他坑

如果你在用 width: max-content 做弹性列宽表格,还需要注意:

  • truncate(即 overflow: hidden)在 max-content 测量阶段会让单元格收缩到 0,改用 whitespace-nowrap 只截断换行,不影响宽度测量
  • w-full 加在单元格内层容器上会和 truncate 打架,要分层处理

一句话外卖

<input>size 属性默认 20,它的内在尺寸参与表格列宽计算且优先级极高,放进筛选行前必须显式设 size={1}