这段声明定义了两个显式列轨道:
.row {
display: grid;
grid-template-columns:
minmax(8rem, 1fr)
minmax(0, 3fr);
}两列并非固定占据 25% 和 75%,而是各自遵循一组宽度规则:
- 左列最窄为
8rem,按1份分配余下空间。 - 右列最窄为
0,按3份分配余下空间。
这种写法适合“标签 + 主内容”布局:左列至少为 8rem,右列取得其余宽度;容器变窄时,右列可以缩窄。
grid-template-columns 描述的是列轨道
grid-template-columns 后面的每个轨道尺寸对应一列:
grid-template-columns: 12rem 1fr;这段代码定义两列。第一列宽 12rem,第二列用 1fr 占据余下空间:
┌──────────────┬──────────────────────────────┐
│ 12rem │ 1fr │
└──────────────┴──────────────────────────────┘如果设置了 column-gap 或 gap,列间距也会占用容器宽度,但不属于任何一列。
fr 按权重分配余下宽度
Grid 扣除固定宽度、最小宽度和列间距后,把余下宽度分给使用 fr 的列。fr 前面的数值表示各列的分配权重,CSS Grid 规范称为 flex factor。CSS Grid Layout Module Level 2:Flexible Lengths
例如:
grid-template-columns: 1fr 2fr;如果没有其他宽度约束,两列按 1 : 2 分配可用宽度:第一列占三分之一,第二列占三分之二。
同理,1fr 3fr 的分配比例是:
1 : 3在没有 gap、两列都未触及下限时,列宽比例为:
左列 = 1 / (1 + 3) = 25%
右列 = 3 / (1 + 3) = 75%fr 不是百分比。这里的 1fr 和 3fr 合计为 4fr,所以分别得到 25% 和 75%;某一列触及下限后,比例随之改变。
minmax() 同时声明下限和上限
minmax(min, max) 为 Grid 轨道设置尺寸范围:第一个参数是下限,第二个参数是上限所用的尺寸函数。第二个参数可以使用 fr,表示该轨道分配余下空间时的权重。CSS Grid Layout Module Level 2:Track Sizing Functions
minmax(8rem, 1fr)这段代码可以读作:
最小轨道尺寸:8rem
弹性系数: 1这里不能按字面比较 8 和 1。8rem 是长度,1fr 是分配权重;后者需要结合容器宽度、其他轨道和间距才能换算成长度。minmax() 比较的是两种规则算出的轨道宽度,而不是单位前面的数字。
rem 相对于根元素的字体大小。只有在根元素计算后的 font-size 为 16px 时,8rem 才等于 128px;它不是固定的像素换算。CSS Values and Units Module Level 4:Font-relative Lengths
容器变宽和变窄时怎样计算
下面用两个容器宽度说明计算过程,并作如下假设:
- 根元素的
font-size是16px,所以8rem = 128px; - Grid 容器宽度是确定值;
- 没有边框、内边距和
gap; - 内容不影响轨道宽度。
容器宽 800px
按 1 : 3 分配:
左列 = 800px × 1 / 4 = 200px
右列 = 800px × 3 / 4 = 600px左列算得 200px,没有触及 128px 的下限,因此两列宽度为 200px 和 600px。
容器宽 400px
先按 1 : 3 计算左列:
400px × 1 / 4 = 100px100px 小于下限,因此左列取 128px,右列使用余下的宽度:
左列 = 128px
右列 = 400px - 128px = 272px下限生效后,两列不再保持 25% : 75%。
为什么右列写成 minmax(0, 3fr)
3fr 单独作为轨道尺寸时,Grid 使用 auto 作为下限,相当于 minmax(auto, 3fr)。这个下限可能取决于网格项(Grid item)的最小宽度,以及内容所需的最小宽度。CSS Grid Layout Module Level 2:Track Sizing Functions
例如,右列中有一段默认不能断行的长字符串:
<div class="row">
<div class="label">Account</div>
<div class="content">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</div>
</div>如果右列写成 3fr,长内容可能把这一列撑宽,超出容器余下的宽度:
.row {
display: grid;
grid-template-columns: 10rem 3fr;
}改成 minmax(0, 3fr) 后,右列下限为 0,内容不再决定轨道的最小宽度:
.row {
display: grid;
grid-template-columns: 10rem minmax(0, 3fr);
}这里变窄的是轨道。超出轨道的内容不会因此自动隐藏、滚动或换行,还需要在网格项上处理溢出:
/* 允许长字符串在必要时断开 */
.content {
overflow-wrap: anywhere;
}
/* 或者保留内容宽度,让当前区域横向滚动 */
.content {
overflow-x: auto;
}
/* 或者裁掉超出区域的部分 */
.content {
overflow: hidden;
}overflow-wrap: anywhere 提供的断行位置会计入 min-content 宽度,适合处理长 URL 或连续字符串。CSS Text Module Level 4:Overflow Wrapping
一个完整的标签与内容布局
<dl class="details">
<div class="details__row">
<dt>Username</dt>
<dd>Youyou</dd>
</div>
<div class="details__row">
<dt>Repository</dt>
<dd>an-extremely-long-repository-name-without-a-normal-break-point</dd>
</div>
</dl>.details {
margin: 0;
}
.details__row {
display: grid;
grid-template-columns:
minmax(8rem, 1fr)
minmax(0, 3fr);
gap: 1rem;
}
.details__row > dt,
.details__row > dd {
margin: 0;
}
.details__row > dd {
overflow-wrap: anywhere;
}gap: 1rem 先占用两列之间的宽度,其余部分再按 1 : 3 分配。左列最窄为 8rem,右列可以变窄,长字符串由 overflow-wrap 断行。
与几种相似写法的边界
| 写法 | 列宽行为 |
|---|---|
25% 75% | 两列按容器宽度的百分比计算,没有 8rem 下限;加上 gap 后,总宽度可能超过容器。 |
8rem 3fr | 左列固定为 8rem;右列占用余下空间,其 auto 下限可能受内容影响。 |
minmax(8rem, 1fr) 3fr | 左列有 8rem 下限,并按比例变宽;右列带有 auto 下限。 |
minmax(8rem, 1fr) minmax(0, 3fr) | 左列有 8rem 下限,两列按 1 : 3 分配余下空间,右列下限为 0。 |
这组声明只控制轨道宽度,不会把两列自动改成上下排列。需要改变排列方式时,还要使用 media query 或 container query。