← 🟩 CSS Grid · 二维布局与轨道模型 / 同一份「配额进度列表」的四种实现对照 待审核 8 / 8
实战 · 三列对齐列表

同一份「配额进度列表」的四种实现对照

一个在后台 / 仪表盘里极常见的诉求:左列名称(随文字长短自适应)、中列进度条(占满中间余量)、右列数值(随内容自适应),且不论名称多长,多行之间三列严格对齐成一条竖线。这恰好是「让分散在多行里的内容对齐到同一组列线」的典型问题。本页用四种方式实现同一份数据并排对照——经典 display: table、表格 + width 技巧、grid + display: contentsgrid + subgrid——逐一拆解各自如何做到对齐与取舍。例子取自 Get Ready for display: contents · css-tricks.com

难点在哪。 把整行交给 flex 很容易让单行内三段排开,但 flex 不知道「别行的名称有多宽」,跨行对不齐。要跨行对齐,必须有一组所有行共享的列轨——下面四种做法,本质都是在回答「谁来定义这组共享列、各行怎么采用它」。

1 · display: table + width:1px(经典做法)

把列表当表格:ultablelitable-row、三段是 table-cell。表格布局天生跨行对齐列(同列所有单元同宽)。再给两侧单元 width: 1px; white-space: nowrap——表格会把它们收缩到恰好容纳内容的宽度,中间没设宽的 bar 单元便吃掉全部余量。这是 subgrid / grid 普及前的主力方案。

2 · display: table + bar 单元 width:100%

同样是表格,但换个方式让中列变宽:不收缩两侧,而是直接给 bar 单元 width: 100%。表格里某单元请求 100% 宽时,会在满足其他单元内容宽度后把剩余宽度尽量给它,效果等同——两侧贴内容、中间占满。与前一种做法是同一思路的两种写法,任选其一。

3 · grid + li { display: contents }

ulgrid-template-columns: auto 1fr auto——auto 贴内容、1fr 吃余量,正好是想要的三列。但 li 隔在中间:不处理的话每个 li 只占一个单元。给 lidisplay: contents 让其盒子消失,三段子元素上浮直接成为父网格的项,于是逐行对齐到三列。代价:li 自身的 border / background 会失效(本例 li 无装饰,无碍)。

4 · grid + li { grid-template-columns: subgrid }

父网格同样是 auto 1fr auto。这次保留 li:让它 grid-column: 1 / -1 占满整行,再 grid-template-columns: subgrid 继承父级的三条列轨。三段作为 li 子网格的项,落在与父网格相同的列线上,跨行对齐。相比 display:contents 做法,它保留了 li 的盒子——可以给行加边框 / 背景 / 圆角 / 事件,语义也更稳。代价是需要浏览器支持 subgrid。

5 · 四种做法对照

做法 谁定义共享列 保留行盒子 行可加边框/背景 主要取舍
table + width:1px 表格算法 兼容性最好;但语义是「表格」,且 table 布局难配 gap / 复杂对齐。
table + width:100% 表格算法 同上,换一种让中列变宽的写法。
grid + display: contents 父 grid 的列轨 否(盒子消失) 扁平、对齐能力强;但 li 装饰失效,语义元素上需测 a11y。
grid + subgrid 父 grid 的列轨 最干净:保留行盒子又跨行对齐;需 subgrid 支持(现代浏览器已普及)。

怎么选。 新项目、面向现代浏览器 → 首选 subgrid(保留行结构 + 对齐,语义最自然);需要兼容很老的环境、或就是表格语义的数据 → 两种 table 做法依然稳;要扁平 DOM、行本身无需任何装饰 → contents 做法简洁。三者背后是同一句话:让所有行采用同一组列轨