CSS Grid Cheatsheet - Template, Areas & Layout Guide
There is only one line between Grid and Flexbox, but crossing it is expensive: control a single axis and use Flex; align rows and columns together and use Grid. Page skeletons, a fixed header plus sidebar and content, or a dashboard of panels, are inherently two-dimensional. Forcing those onto nested Flex containers means three levels of wrappers just to line up columns, and the stylesheet collapses into indirection quickly. Size tracks with fr and minmax rather than percentages: fr shares leftover space in proportion, and minmax(200px, 1fr) gives each column a floor while keeping it flexible, so auto-fit and auto-fill produce responsive behaviour with no media queries at all. Sections cover the container, spacing and alignment, placing and spanning items, explicit and implicit tracks, common patterns, and responsive techniques, including grid-template-areas, which trades a little flexibility for a layout you can read at a glance. Naming tracks and areas with grid-template-areas costs some flexibility and buys a layout a colleague can read without tracing selectors.
Typical Use Case
For engineers laying out whole pages rather than one component: dashboards, card walls, galleries and form grids. Grid lets the parent define tracks while children declare where they land, instead of nested floats or piles of calc. Four groups: container definitions with repeat and named areas, spacing and alignment through gap and the justify and align families, spanning cells with line numbers and span, and implicit tracks. The traps are auto-fill versus auto-fit and 1fr inside minmax.
Container Definition 8
display: griddisplay: inline-gridgrid-template-columns: 1fr 2fr 1frgrid-template-rows: 100px auto 100pxgrid-template-columns: repeat(3, 1fr)grid-template-columns: repeat(auto-fill, minmax(200px, 1fr))grid-template-columns: repeat(auto-fit, minmax(200px, 1fr))grid-template-areas: "header header" "sidebar main" "footer footer"Gap & Alignment 10
gap: 16pxrow-gap: 16pxcolumn-gap: 16pxjustify-items: stretchjustify-items: centeralign-items: centerplace-items: centerjustify-content: centeralign-content: centerplace-content: centerCells & Spans 7
grid-area: headergrid-area: 1 / 1 / 3 / 3grid-column: 1 / 3grid-row: 1 / span 2grid-column: 1 / -1grid-column: span 2grid-row: span 3Explicit & Implicit Tracks 6
grid-auto-columns: 100pxgrid-auto-rows: 100pxgrid-auto-flow: rowgrid-auto-flow: columngrid-auto-flow: densegrid-auto-flow: row denseCommon Patterns 6
grid-template-columns: 1fr 1fr 1frgrid-template-columns: 200px 1frgrid-template-columns: repeat(12, 1fr)grid-template-columns: minmax(0, 1fr) minmax(0, 1fr)grid-template-areas: "header" "main" "footer"grid-column: 1 / -1Responsive Tips 5
repeat(auto-fit, minmax(200px, 1fr))repeat(auto-fill, minmax(150px, 1fr))repeat(auto-fit, minmax(min(100%, 250px), 1fr))@media (max-width: 768px) { grid-template-columns: 1fr }grid-auto-rows: minmax(150px, auto)Parameter matrix
| Parameter | Effect | Example |
|---|---|---|
display: grid | 把容器变成网格格式化上下文,direct child 自动成为网格项 | display: grid |
display: inline-grid | 网格按行内块参与外层排版,宽度收缩到内容,适合嵌在文字流里的小控件 | display: inline-grid |
grid-template-columns: 1fr 2fr 1fr | 显式列轨道,fr 分配剩余空间;三列布局最常见的一行 | grid-template-columns: 1fr 2fr 1fr |
grid-template-rows: 100px auto 100px | 显式行轨道,auto 行由内容撑开;固定行与自适应行混排的经典写法 | grid-template-rows: 100px auto 100px |
grid-template-columns: repeat(3, 1fr) | 把一段轨道定义重复 N 次,避免手写长串 1fr | grid-template-columns: repeat(3, 1fr) |
repeat(auto-fill, minmax(200px, 1fr)) | 按容器宽度自动决定列数:空轨道也会被填充,所以容器变窄时最后一行项目左侧对齐 | grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)) |
repeat(auto-fit, minmax(200px, 1fr)) | 同上但会折叠空轨道,容器变宽时项目被拉伸铺满,是响应式卡片墙的首选 | grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)) |
grid-template-areas | 用字符串矩阵给区域命名,配合 grid-area 摆放,页头/侧栏/主体的经典三段式 | grid-template-areas: "header header" "sidebar main" "footer footer" |
gap / row-gap / column-gap | 轨道间距,取代 margin hack,且不会在容器边缘产生外边距 | gap: 16px |
justify-items / align-items | 控制网格项在其轨道内的对齐:justify 沿行内轴,align 沿块轴 | align-items: center |
justify-content / align-content | 控制整组轨道在容器内的分布,项数少于轨道数时才有效果 | justify-content: center |
place-items / place-content | align 与 justify 的简写,一次设两个轴 | place-items: center |
grid-area: 1 / 1 / 3 / 3 | 用起止线一次声明跨行跨列,顺序是 行起 / 列起 / 行止 / 列止 | grid-area: 1 / 1 / 3 / 3 |
grid-column: 1 / 3 | 显式跨列;写成 1 / -1 表示从第一列贯穿到最后,是通栏的常用写法 | grid-column: 1 / -1 |
grid-row: 1 / span 2 | 从第 1 行起跨 2 行,span 写法不依赖总行数,改版时更稳 | grid-row: 1 / span 2 |
grid-column: span 2 | 只声明跨度不给起点,由自动放置算法决定落在哪,是自适应磁贴布局的关键 | grid-column: span 2 |
grid-auto-rows: 100px | 设定隐式行的高度;不加时隐式行由内容决定,卡片高度容易参差 | grid-auto-rows: 100px |
grid-auto-columns: 100px | 设定隐式列的宽度,横向滚动容器里常用 | grid-auto-columns: 100px |
grid-auto-flow: row / column | 决定自动放置方向,row 是逐行填充,column 是逐列填充 | grid-auto-flow: column |
grid-auto-flow: dense | 回填空洞:小项能塞进前面留下的空位,代价是视觉顺序与 DOM 顺序脱节 | grid-auto-flow: dense |
grid-template-columns: 200px 1fr | 固定侧栏 + 弹性主内容,后台管理页最常用的一行 | grid-template-columns: 200px 1fr |
grid-template-columns: repeat(12, 1fr) | 12 列栅格,用 grid-column: span N 做按比例分栏,比手写百分比可靠 | grid-template-columns: repeat(12, 1fr) |
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) | 把 fr 的最小值钉成 0,等价于允许收缩,避免长内容把轨道撑破 | grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) |
repeat(auto-fit, minmax(min(100%, 250px), 1fr)) | min(100%, 250px) 保证窄屏下单列不会被 250px 的最小值撑出横向滚动 | grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)) |
@media (max-width: 768px) { grid-template-columns: 1fr } | 断点处从多列塌成单列,是 Grid 响应式最省事的落点 | @media (max-width: 768px) { grid-template-columns: 1fr } |
grid-auto-rows: minmax(150px, auto) | 隐式行给一个最小高度并允许内容撑高,磁贴墙两边都照顾到 | grid-auto-rows: minmax(150px, auto) |
Common pitfalls
Symptomauto-fill 与 auto-fit 看起来一样,但最后一行项目没有铺满整行。
Causeauto-fill 保留空轨道(1fr 仍分到空间),auto-fit 才折叠空轨道把空间让给已有轨道。
Fix需要铺满用 auto-fit,需要保持对齐(背景条纹、序号列)用 auto-fill。
Symptom窄屏下页面出现横向滚动条,内容被裁掉一半。
Causeminmax(200px, 1fr) 的 200px 是硬下限,视口小于 200px 时轨道仍保持 200px。
Fix下限写成 min(100%, 200px),或在断点处把 grid-template-columns 改成 1fr。
Symptom某一列被一段很长的 URL 或代码块撑得特别宽,其它列被挤扁。
Causefr 的下限其实是 auto,即内容最小尺寸;长单词或 nowrap 会把轨道顶开。
Fix给内容加 overflow-wrap: anywhere,或把轨道写成 minmax(0, 1fr) 从根上允许收缩。
Symptom子项设了 grid-column: 1 / 3 却没跨到预期位置,元素出现在下一行。
Causegrid-area 与 grid-column/grid-row 的四个值顺序是 行起/列起/行止/列止,与书写直觉相反。
Fix逐值确认行列次序,或改用更不易错的 grid-column 与 grid-row 分别声明。
Symptom项目高度参差不齐,卡片底部对不齐。
Cause隐式行高度由内容决定,行高不一致;只设了 align-items 而没管行轨道。
Fix用 grid-auto-rows: minmax(150px, auto) 给隐式行统一下限,或改用显式行模板。
Symptom加了 dense 之后 tab 顺序 / 朗读顺序与视觉顺序不一致。
Causedense 会让后面的项目被回填到前面的空位,DOM 顺序与视觉位置脱节。
Fix依赖焦点顺序与读屏顺序时不要用 dense,改用显式 grid-column 指定每个磁贴位置。
Symptomgrid-template-areas 布局在某处突然塌成一列。
Causeareas 字符串里的空格与换行必须严格对齐行列,某一行的字符串数量少于其它行就会导致该行非法。
Fix保证每行 areas 的 token 数一致、同一区域名构成矩形,必要时用 minmax(0, 1fr) 兜底。
Symptom嵌套 grid 时内层网格的 gap 与外层叠加,实际间距是两倍。
Causegap 不是可继承的 margin,父子都设了 gap 就会各自生效。
Fix明确哪一层负责间距(通常外层),内层只设 padding。
Troubleshooting
1确认容器确实成为网格格式化上下文
grep -n "display: grid" -r srcdisplay 写在了子项而不是容器上是无效的。
2把 areas 定义与 grid-area 命名对照检查
grep -n "grid-template-areas\|grid-area" -r src命名拼写不一致时该区域会被当作未命名的普通网格项处理。
3找出引入横向滚动的元素
grep -n "minmax(" -r srcminmax 的下限大于视口宽度是最常见的溢出源。
4排查 dense 是否破坏了焦点顺序
grep -n "dense" -r src有 dense 就需要确认 DOM 顺序与视觉顺序一致。
5统一检查断点处的塌列规则
grep -n "max-width: 768px" -r src确认每个多列容器都有对应的单列覆盖。
6核对隐式行是否都已设定高度
grep -n "grid-auto-rows" -r src缺它时行高由内容决定,是卡片墙高度参差的根源。
Command Examples
Named areas for a whole-page layout
.layout {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 200px 1fr;
gap: 16px;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }Named areas separate layout from placement: the parent declares the structure once and children only announce a name, so visual order survives HTML reordering. That pays off in responsive work: collapse the template to one column on small screens and give each area a single grid-area, with no child changes at all.
auto-fit cards with no media query
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
}auto-fit drops columns as the container narrows and collapses empty tracks, distributing the leftover space to the remaining ones, so cards always fill the width; auto-fill keeps empty tracks reserved, leaving a gap at the end of a row. Use auto-fill when the last row should not stretch.
minmax(0, 1fr) stops content from bursting the track
.grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}A 1fr track has an automatic minimum, meaning it must still fit its content; a long URL or nowrap string blows the track past the container and breaks the layout. minmax(0, 1fr) explicitly allows shrinking to zero and lets overflow handling inside do the work — the standard fix for overflow in a two-column grid.
Line-based placement for spanning items
.card {
grid-column: 1 / -1; /* 跨满整行 */
}
.wide {
grid-column: 1 / 3; /* 跨 2 列 */
}
.tall {
grid-row: 1 / span 3; /* 从第 1 行起跨 3 行 */
}Lines are 1-based and -1 means the last line. grid-column: 1 / -1 is the sturdier way to say "span the full row": unlike span N it survives a template change from three columns to two, whereas span 3 would extend past the grid.
Implicit tracks and dense packing
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(150px, auto);
grid-auto-flow: row dense;
}When children outnumber the explicit columns, implicit tracks appear with a height fixed by grid-auto-rows, which clips content; minmax(150px, auto) gives a floor while letting content grow. row dense backfills later items into earlier holes for a tidier look, but visual order then differs from DOM order, which matters for keyboard and screen-reader navigation.
Common Pitfalls
- A fr track has an automatic minimum: a long URL, non-wrapping text, or a fixed-width image pushes the track past the container and produces a horizontal scrollbar. Use minmax(0, 1fr) instead of 1fr in any layout of two columns or more.
- The strings in grid-template-areas must form rectangles with an identical column count per row. Missing one cell makes the browser drop the whole rule and the layout silently collapses to normal block flow, which looks like "I added areas and nothing happened".
- align-items / justify-items position items inside their cells, while justify-content / align-content position the whole grid inside the container; the two pairs are unrelated. If the grid will not centre and you keep writing justify-items: center, that is the wrong property.
- After display: grid, child margins no longer inflate track sizing because tracks are computed from the content box, so layering large margins produces phantom gaps. Express spacing with gap and stop stretching layouts with margins.
- Browsers without grid support collapse the page to single-column flow rather than erroring. If IE or old Android WebView still matter, wrap the rules in @supports (display: grid) and provide a flex fallback.
- grid-auto-flow: dense breaks the correspondence between visual and DOM order, so Tab focus jumps around and screen readers announce a different sequence than the eye sees. Reserve it for purely decorative galleries with no focusable interactive children.
Tips
- fr is a flexible unit — 1fr 2fr means the second column is twice as wide as the first.
- minmax(200px, 1fr) means min 200px, max flexible fill; pair with auto-fill for responsiveness.
- grid-template-areas defines layout visually, improving code readability.
- gap replaces the old grid-gap and is the current standard syntax.
- auto-fit collapses empty tracks to stretch and fill; auto-fill keeps them — responsive layouts usually use auto-fit.
FAQ
What is the actual difference between auto-fill and auto-fit, and which one for responsive columns?
Both generate responsive columns via repeat(auto-xxx, minmax(200px, 1fr)); the difference shows up when the container has spare width. auto-fill keeps the empty tracks, so when you have fewer cards than columns the widths stay put and the row looks padded on both sides. auto-fit collapses the empty tracks and hands their space to the remaining ones, filling the row. Use auto-fit for fluid card grids whose item count varies, and auto-fill when a dashboard list needs a fixed-width column skeleton.
Content keeps blowing out my 1fr tracks — how do I fix it?
A 1fr track has an automatic minimum size, so a long unbreakable child can stretch it beyond the intended ratio. Writing minmax(0, 1fr) minmax(0, 1fr) forces the minimum to zero so the tracks divide space exactly as specified, and you handle the long content with wrapping or overflow instead. The same applies to grid-template-columns: 200px 1fr — swap that 1fr for minmax(0, 1fr) whenever the main column may contain wide content.
Should I use grid-template-areas or manual grid-column spans?
It depends on whether the layout shape is fixed. For stable page skeletons use grid-template-areas: "header header" "sidebar main" "footer footer" and let each child declare grid-area: header — the stylesheet then reads like a diagram and stays easy to maintain. For content whose position changes constantly and needs irregular placement, address the lines directly: grid-area: 1 / 1 / 3 / 3 is row-start / column-start / row-end / column-end, grid-column: 1 / -1 spans the full row, and grid-row: 1 / span 2 means two rows starting at line 1.
How do justify-items and justify-content differ, and which one do I edit?
They act at different levels. justify-items aligns the child inside each grid cell; justify-content aligns the whole set of tracks inside the container. If the content of a cell is not centered, change justify-items: center or place-items: center. If the tracks themselves are not centered in the container, change justify-content: center or place-content: center. The mental order is: align the tracks (content) first, then align what sits inside each cell (items).
Auto columns get squeezed into a sliver on small screens — how do I stop the horizontal overflow?
Use two levers together. First, wrap the minimum in min() as a floor: repeat(auto-fit, minmax(min(100%, 250px), 1fr)), so the track can never exceed the container width no matter how narrow the viewport gets. Second, at narrow breakpoints collapse to a single column with @media (max-width: 768px) { grid-template-columns: 1fr }, and reorder your grid-template-areas at the same time if needed. For row sizing, grid-auto-rows: minmax(150px, auto) lets rows grow with their content.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us