使用方法
- 填「列数」(1 ~ 12,示例 4)。上限 12 是实用边界:超过 12 列后单列宽低于 80px,中文标题会被逐字换行。
- 填「最小轨道宽」(80 ~ 600 px,示例 180)。这个值只在
auto-fill/auto-fit模式下生效,固定列数模式下会被忽略。 - 填
gap(0 ~ 80,示例 16)与容器padding(0 ~ 60,示例 16)。这两个值直接吃掉可用宽,是最容易被忽略的部分。 - 选轨道写法:
auto-fill、auto-fit、固定列数1fr、或minmax(0, 1fr)。四者的差别在下面「原理和变量」里逐条讲。 - 点「生成 CSS」(三个都是单行数字框,按 Enter 直接生成)。结果区会给出按 1200px 容器实算的列数、每列宽度与
content-box溢出量。
这个 CSS网格生成器能解决什么问题
一是把「几列」换算成「该写多少 px」。多数人卡在 minmax() 的第一个参数上:想让 1200px 容器排 4 列,直觉答案是写 300px,但 gap 吃掉了 3 × 16 = 48px,写 300px 只会排出 3 列。实测反解区间是 228 ~ 288px(大于 227.2、不超过 288)——写 289px 就掉回 3 列。本页把这个区间和实得列数都算出来。
二是分清 auto-fill 与 auto-fit。这是两个最容易混的关键词:auto-fill 保留空轨道,auto-fit 把空轨道折叠为 0。实测在 1200px 容器、最小轨道 150px 下两者都算出 7 列,但只放 3 个子项时,auto-fill 每条仍是 157.71px(右侧空 630.9px),auto-fit 则塌成 3 条、每条 389.33px 撑满整行。子项数 ≥ 列数时两者完全等价。
三是诊断横向溢出。页面出现横向滚动条时,最常见的原因不是列数太多,而是默认 box-sizing: content-box:grid 分配给子项的是内容盒宽,padding 加在这个宽度之外。实测容器 1000px、padding 24px、gap 16px、卡片 padding 16px 时,4 列的溢出量正好是 4 × 32 = 128px,且与容器宽无关——2 列溢出 64px、6 列溢出 192px,线性于列数。
四是给「长串内容」一个不会撑破的写法。轨道写成 1fr 时最小值是 auto,会解析到 min-content;放一个 1400px 宽的 URL 时,容器 1200px 会被撑到 1616px(1.35 倍),横向滚动条立刻出现。改成 minmax(0, 1fr) 后最小值被显式压成 0,轨道恒为 984px,溢出交给 overflow 处理。
本页不做这些事:不生成 Flexbox 布局(那是CSS Flexbox布局生成器的事,两者的一维/二维模型不同)、不排版格式化已有 CSS(用CSS格式化美化)、不生成阴影与圆角。要阴影用CSS长方体阴影生成器,要圆角用CSS圆角生成器。
原理和变量
1. fr 的分配算法。规范里的 fr 是剩余空间的分数,不是「均分容器」。算法是:可用宽 = 容器宽 − padding − gap × (列数 − 1),然后每 fr = 可用宽 / fr 总数。实测 1200px 容器、gap 16px、三条 1fr:可用宽 = 1200 − 16 × 2 = 1168px,每列 1168 ÷ 3 = 389.33px,验算 3 × 389.33 + 32 = 1200 ✓。改成 2fr 1fr 1fr:每 fr = 1168 ÷ 4 = 292px,2fr 列得 584px、两个 1fr 列各 292px。
2. 1fr 与 minmax(0, 1fr) 的区别。裸写 1fr 时轨道的最小值是 auto,最终解析为 min-content(受自动最小尺寸规则影响)。所以在 grid-template-columns: 200px 1fr 里,如果第二格放的是不可断的长串,轨道会被 min-content 顶大。实测容器 1200px、第二格 min-content 为 1200px 时溢出 216px,为 1400px 时溢出 416px;写成 minmax(0, 1fr) 后轨道恒为 1200 − 200 − 16 = 984px,容器不再横向溢出。
3. 列数公式。repeat(auto-fill, minmax(MINpx, 1fr)) 的列数按 n = floor((容器宽 + gap) / (MIN + gap)) 算,最少 1。实测 MIN = 150、gap = 16 时:360px → 2 列、640px → 3 列、768px → 4 列、1024px → 6 列、1200px → 7 列、1440px → 8 列。注意 1024 → 6 列直接跳过了 5 列,因为 floor 的结果就是这样,不存在「5 列」这个中间态。
4. gap 与 padding 怎么吃掉列宽。在 1200px 容器、padding 24px 下:2 列时 gap 0 → 每列 576px、gap 16 → 568px;4 列时 gap 0 → 288px、gap 16 → 276px;6 列时 gap 0 → 192px、gap 16 → 178.67px。每列的损失是 16 × (列数 − 1) / 列数——列数越多损失越大,但总和恒为 1152px。
5. minmax() 的三种写法与失效条件。规范规定 minmax() 的最小值只能是 <length-percentage> 或 auto,不能是 fr,也不能是 min-content / max-content。所以 minmax(1fr, 1fr) 是无效 CSS,整条声明被丢弃——注意不是「回退到默认值」,是「这条规则不存在」。最大值则可以取 fr、min-content、max-content、none。auto-fill 与显式列数混用(repeat(3, 1fr) auto-fill)同样整条丢弃。
6. 为什么本页坚持显式断点。只用 auto-fit 时列数随容器宽连续变化,在 640px 与 1000px 之间会出现无法用媒体查询覆盖的中间态。规范推荐的写法是「默认 1 列 → @media(min-width:640px) 2 列 → @media(min-width:1000px) 4 列」,保证三个可预测、可截图对比的状态。360px 宽下容器 padding 16px × 2 = 32px,1 列内容宽 328px,无横向滚动。
完整示例
默认这组:列数 4、最小轨道 180px、gap 16px、padding 16px、行高 1.5、auto-fill 模式(数值仅作演示)。
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr))- 按 1200px 容器实算:
n = floor((1200 + 16) / (180 + 16)) = floor(6.204) = 6列(不是 4 列——最小轨道只决定「每列至少多宽」,排几列由容器宽决定) - 可用宽 = 1200 − 16 × 2(padding)− 16 × 5(gap,5 个间隙)= 1088px,每列 1088 ÷ 6 = 181.33px
- 若要真正排出 4 列,最小轨道需落在 228 ~ 288px:
floor(1216 / 244) = 4,而floor(1216 / 305) = 3(289px 就掉到 3 列) content-box下若子项也有 16px padding,6 列的溢出量 = 6 × 32 = 192px
下方表格里 4 列那行可以直接对照:gap 0 → 288.00px、gap 16 → 276.00px,每列少 12px。
输入范围与对照表
五个输入框的约束:列数 min="1" max="12" step="1"、最小轨道 min="80" max="600" step="1"、gap min="0" max="80" step="1"、padding min="0" max="60" step="1"、行高 min="1" max="3" step="0.1"。0 在 gap 与 padding 上是合法值(就是不要间隙),但列数下限是 1——repeat(0, 1fr) 在 CSS 里非法。
| 列数 | gap (px) | 容器 (px) | 可用宽 (px) | 每列宽 (px) | 每列少 (px) |
|---|---|---|---|---|---|
| 2 | 0 | 1200 | 1152 | 576.00 | 0.00 |
| 2 | 16 | 1200 | 1136 | 568.00 | 8.00 |
| 3 | 0 | 1200 | 1152 | 384.00 | 0.00 |
| 3 | 16 | 1200 | 1120 | 373.33 | 10.67 |
| 4 | 0 | 1200 | 1152 | 288.00 | 0.00 |
| 4 | 16 | 1200 | 1104 | 276.00 | 12.00 |
| 5 | 0 | 1200 | 1152 | 230.40 | 0.00 |
| 5 | 16 | 1200 | 1088 | 217.60 | 12.80 |
| 6 | 0 | 1200 | 1152 | 192.00 | 0.00 |
| 6 | 16 | 1200 | 1072 | 178.67 | 13.33 |
| 8 | 0 | 1200 | 1152 | 144.00 | 0.00 |
| 8 | 16 | 1200 | 1040 | 130.00 | 14.00 |
| 10 | 0 | 1200 | 1152 | 115.20 | 0.00 |
| 10 | 16 | 1200 | 1008 | 100.80 | 14.40 |
| 12 | 0 | 1200 | 1152 | 96.00 | 0.00 |
| 12 | 16 | 1200 | 976 | 81.33 | 14.67 |
默认 12 行服务端直出,点「加载更多行」补到 16 行。容器固定 1200px、padding 24px,所以「可用宽」随列数与 gap 变化;4 列 + gap 16 那行标蓝,就是正文里引用的那组数。
几个常见误用的对照:
- 想让 1200px 排 4 列,最小轨道写 300px → 实得 3 列。要 4 列得写 228 ~ 288px。
- 子项有 padding,页面出现横向滚动 → 加
box-sizing: border-box。溢出量 = 列数 × padding × 2。 - 放长 URL 的格子被撑宽 → 轨道改
minmax(0, 1fr),并给该格加overflow: hidden。 - 只有 3 个卡片却留一大片空白 →
auto-fill换成auto-fit,空轨道会折叠。
边界与精度
1. 反解「几列对应多少 px」的正确区间。由 n = floor((1200 + 16) / (MIN + 16)) = 4 得 4 ≤ 1216/(MIN+16) < 5,即 243.2 < MIN + 16 ≤ 304,MIN ∈ (227.2, 288]。实测 MIN = 240 → 4 列、MIN = 288 → 4 列、MIN = 289 → 只剩 3 列。所以「1200 / 4 = 300」是错的直觉答案。
2. content-box 的溢出量是列数的线性函数。容器 1000px、padding 24px、gap 16px、卡片 padding 16px 时实测:2 列溢出 64px、3 列 96px、4 列 128px、6 列 192px——都等于「列数 × 32px」,与容器宽无关。这解释了为什么「宽屏没事、窄屏有滚动条」或反之:变的其实是列数,不是容器。
3. minmax() 写错是静默失效。minmax(1fr, 1fr)、minmax(min-content, 1fr) 都违反规范,整条 grid-template-columns 声明被丢弃,元素退回单列(无模板的默认网格)。没有报错、没有回退值,所以本页输出的写法都是规范允许的组合。
4. 列数上限取 12 的理由。12 是 Bootstrap 的栅格上限。超过 12 列后单列宽低于 80px,中文标题(每字 20px)一行放不下 4 个字,会被逐字换行,实用价值为零。这不是规范限制,是排版可读性限制。
5. 容器宽按 1200px 固定计算。真实页面宽度随视口变化,所以「实得列数」是以 1200px 为基准的估算,用于横向比较不同参数组合。精确列数要用 ResizeObserver 量实际容器——本页不做,那需要常驻监听且在多栏布局里没有唯一答案。
6. 行高只影响子项,不影响轨道。line-height 加在 .grid > * 上,只改变文字行距与子项高度,不参与轨道宽度的计算。所以调行高不会改变「每列宽」那几格数字——这一点在响应式微调时经常被误解。
常见问题
auto-fill 和 auto-fit 到底差在哪?我该用哪个?
只差在空轨道怎么处理:auto-fill 保留空轨道(列数照算,子项按顺序从左往右排),auto-fit 把空轨道折叠成 0(元素会撑满)。实测 1200px 容器、MIN 150px 时两者都算出 7 列,但只放 3 个子项:auto-fill 每列 157.71px、右侧空 630.9px;auto-fit 塌成 3 列、每列 389.33px。元素数量会变化就用 auto-fit,数量固定或不确定用 auto-fill。子项数 ≥ 列数时两者完全等价。
为什么我写 minmax(300px, 1fr) 结果只有 3 列,不是预期的 4 列?
因为 gap 不在你的除法里。列数公式是 floor((容器宽 + gap) / (MIN + gap)),不是 floor(容器宽 / MIN)。1200px 容器、gap 16px、MIN 300 时:floor(1216 / 316) = floor(3.85) = 3。要 4 列,MIN 必须落在 228 ~ 288px。这是本页最主要的功能——把「我想要几列」换算成「该写多少 px」。
页面出现横向滚动条,但列数明明只有 4 列,为什么?
最可能是 box-sizing。默认 content-box 下,grid 分配给子项的是内容盒宽度,子项的 padding 加在这个宽度之外。实测容器 1000px、padding 24px、gap 16px、卡片 padding 16px 时,4 列溢出正好 128px(= 4 × 32),且与容器宽无关。修法是给子项加 box-sizing: border-box;给轨道写 minmax(0, 1fr) 只能解决 min-content 问题,解决不了 padding。
1fr 明明写了「平分」,为什么格子会被内容撑破?
因为 1fr 的最小值是 auto,最终解析为 min-content。在 200px 1fr 这种组合里,如果 1fr 那格放的是不可断的长串(URL、无空格的英文标识符),轨道会被顶大。实测容器 1200px、min-content 1400px 时,不写 minmax 会撑到 1616px(1.35 倍);写成 minmax(0, 1fr) 后轨道恒为 984px,溢出交给 overflow。所以凡是有长串内容的格子,轨道都该用 minmax(0, 1fr)。
我写了 minmax(1fr, 1fr),浏览器为什么不认?
因为规范规定 minmax() 的最小值不允许是 fr,也不允许是 min-content / max-content,只能是 <length-percentage> 或 auto。所以 minmax(1fr, 1fr) 是无效声明,整条 grid-template-columns 被丢弃——注意不是「回退到某个默认值」,是「这条规则不存在」,元素会退回无模板的默认单列。最大值才可以取 fr。这种静默失效最难查,所以本页输出的写法都限制在规范允许的组合内。
子项之间的 gap 是加在轨道之间还是轨道里面?
加在轨道之间,不占轨道宽度。所以 4 列 + gap 16px 的实际占用是 4 × 轨道宽 + 3 × 16——只有 3 个间隙,不是 4 个。这正是「1200/4 = 300」不对的原因:(1200 − 48) / 4 = 288px 才是每列实得宽度。行方向同理,gap 也可以写成 gap: 16px 24px(先行后列)两个值。
为什么不用 auto-fit 一把梭,还要写媒体查询?
因为 auto-fit 的列数随容器宽连续变化,会在两个断点之间产生大量无法枚举的中间态(比如 768px 时是 3 列、769px 时突然变 4 列),截图对比和回归测试都很难做。规范推荐「默认 1 列 → @media(min-width:640px) 2 列 → @media(min-width:1000px) 4 列」,好处是三个状态都可预测、可断言。代价是宽屏上浪费空间——所以实际项目里常两者混用:断点管大布局,auto-fit 管大布局内部的次级网格。
行高改了,为什么「每列宽」那几格数字一点没变?
因为行高不参与轨道宽度计算。轨道宽只由容器宽、gap、padding 和 fr 分配决定;line-height 加在 .grid > * 上,只影响文字行距与子项的高度。想改宽度就调列数、gap、padding 或最小轨道宽;想改高度才动行高。这两件事在响应式微调时经常被混在一起改,结果改了一处另一处不动。
相关工具
- CSS Flexbox布局生成器:一维布局用 Flexbox,二维布局才用 Grid,两者不能互相替代。
- CSS格式化美化:已有 CSS 需要重排缩进与展开时用,本页只生成新规则。
- CSS圆角生成器:给生成出来的卡片配圆角。
- CSS长方体阴影生成器:给网格卡片加阴影,让层次更清楚。
- 渐变色生成器:给格子或卡片配渐变背景。
- CSSButton生成器:网格里常放按钮,样式单独生成更方便。
- Glassmorphism生成器:毛玻璃卡片放进网格时用,注意它的
backdrop-filter在旧浏览器上会失效。