先记住这个答案
fr 是弹性轨道的份额,不是容器宽度的百分比。Grid 会先算确定的轨道宽度与列间距,再按比例分配尚可使用的宽度。比如容器内容盒宽 600px,第一列 200px,两列之间的 gap 为 20px,第二列写 1fr,它通常分到 380px。若第二列有不能断开的长内容,自动最小尺寸还可能让它变宽。
fr分的是可用空间,不是容器总宽- 固定轨道和
gap会先占用宽度 1fr默认可能被长内容撑大- 需要强制收缩时用
minmax(0, 1fr)
固定列和弹性列一起算
后台页面常见的布局是一列固定侧栏加一列正文。要算正文宽度,先看容器的内容盒,再扣侧栏和间距。边框和内边距是否算在给定的 600px 中,取决于容器的 box-sizing;不要把外框宽度直接拿来计算。
.layout {
display: grid;
width: 600px;
grid-template-columns: 200px 1fr;
column-gap: 20px;
}
/* 内容盒宽 600px 时,第二列通常是 380px */改成 grid-template-columns: 200px 1fr 2fr 时,先扣固定列和两道间距,余下 360px 被分成三份:后两列分别得 120px 与 240px。两段 fr 之比是 1:2,不能把固定列一起带进这个比例。
长内容为什么会改变结果
实际页面里,一列写了 1fr 却发生横向滚动,常见原因是这一列放了长 URL、代码块或设了 white-space: nowrap 的文字。1fr 可视为带自动最小值的弹性轨道;内容的最小宽度可能阻止它继续缩小。此时不是 fr 计算失灵,而是轨道先要满足最小尺寸。
如果布局要求正文严格留在可用宽度里,可以把列改为 minmax(0, 1fr),允许轨道突破自动最小值。接着还要处理内容自身:长文本用 overflow-wrap: anywhere,图片用 max-width: 100%,代码区可设横向滚动。轨道能变窄并不等于内容会自动裁剪或换行。
假设容器内容宽 900px,左栏固定 200px,沟槽 20px,右栏写 1fr,在无额外最小尺寸约束时右栏拿约 680px。若再加入第二条 1fr 轨道,两条弹性轨道分同一份余量,而不是各自再从 900px 里取一次。长图片可能抬高某条轨道的下限,导致实际结果偏离这个简化算式;此时要连同 minmax() 与内容溢出检查。
容易答错的地方
- 把
1fr当作百分之百 fr的基数是分配给弹性轨道的空间。固定列、内边距和gap已经占去一部分,1fr不等于容器总宽的 100%。- 认为
1fr 1fr一定视觉等宽 - 当某列的自动最小尺寸超过均分份额,实际轨道可能被内容撑开。要实现等宽且可收缩的卡片列,通常写成
repeat(2, minmax(0, 1fr)),同时检查内容溢出。
面试官还会怎么问?
2fr 一定是 1fr 的两倍宽吗?
只有在相同约束下分配可用空间时才能这样说。若某列有较大的最小尺寸,算法须先满足约束,最后轨道宽度未必严格是 1:2。
gap 会产生首尾留白吗?
不会。它只位于相邻轨道之间;首尾空间由容器内边距或轨道整体对齐决定。
minmax(0, 1fr) 能直接修好文字溢出吗?
它解决的是轨道不肯缩小的问题。内容仍可能越过格子,需要另外设置换行、滚动或裁剪策略。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。