CSS Grid Layout: Two-Dimensional Tracks, Areas & Auto-Fit Grids
While Flexbox excels at aligning items along one axis at a time (a single row or column), CSS Grid is a full two-dimensional layout engine. It lets you define explicit rows and columns simultaneously from the container down—making page shells, dashboards, and responsive card galleries crisp and concise.
1. Defining Columns, Rows, and Fractional Units (fr)
Enabling Grid requires only display: grid; on the parent container. You then declare track sizes using grid-template-columns and grid-template-rows. The dedicated fr unit represents a fraction of available free space inside the grid container:
/* Fixed 260px sidebar paired with fluid main workspace */
.lesson-layout {
display: grid;
grid-template-columns: 260px 1fr;
gap: 28px;
}
/* Three equal-width columns regardless of text length */
.stats-cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
Unlike percentages, combining fixed values and fr units (like 260px 1fr) works automatically even when gap: 28px is present, because Grid subtracts all gaps first before dividing remaining space among fr tracks.
2. Responsive Auto-Fit Card Grids Without Media Queries
One of the most useful patterns in modern CSS Grid builds a completely responsive gallery in a single declaration by combining repeat(), auto-fit, minmax(), and min():
.catalog-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
gap: 24px;
}
Here is why wrapping 280px inside min(280px, 100%) matters: on wide desktops, cards sit side-by-side in multi-column rows at least 280px wide, stretching evenly to fill the container. On very small 240px or 320px viewports with tight padding, min(280px, 100%) caps the minimum track at 100% so cards never cause horizontal scrolling.
3. Naming Regions with grid-template-areas
For full-page dashboards and article layouts, grid-template-areas lets you sketch your layout visually right inside CSS:
.page-shell {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
gap: 20px;
}
.page-header { grid-area: header; }
.page-sidebar { grid-area: sidebar; }
.page-main { grid-area: content; }
.page-footer { grid-area: footer; }
@media (max-width: 768px) {
.page-shell {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"content"
"sidebar"
"footer";
}
}
4. Grid vs. Flexbox: Which One Should You Pick?
| Scenario | Recommended Tool | Reason |
|---|---|---|
| Header navbar, button groups, tag pills | Flexbox | Items size naturally from their text width along one axis. |
| Course catalogs, card dashboards, page shells | CSS Grid | Maintains crisp row and column alignment across uneven card lengths. |
| Inside an individual card | Both together | Use CSS Grid for the outer card matrix and display: flex; flex-direction: column; inside each card to pin the CTA button to the bottom. |
5. Spanning Multiple Columns, Centering & auto-fit vs. auto-fill
Once tracks are declared, individual child items can break out of single cells without extra HTML wrappers. Use grid-column: span 2; or grid-column: 1 / -1; (full width from the first grid line to the final edge line) to highlight flagship bento cards or section banners across your grid.
/* Bento dashboard card highlighting a primary module */
.bento-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
gap: 20px;
}
.bento-featured {
grid-column: 1 / -1; /* Spans entire grid width safely at any breakpoint */
}
/* Effortless 2-line vertical & horizontal centering */
.centered-stage {
display: grid;
place-items: center;
min-height: 240px;
}
auto-fitvs.auto-fill: Both fit as many columns as will satisfy the minimum width. However, when fewer items exist than columns available on a wide monitor,auto-fitcollapses empty trailing tracks to0pxso existing cards stretch neatly across the row, whereasauto-fillpreserves empty column slots on the right to maintain strict fixed card widths.- Watch out for Grid Track Blowouts: A grid track written as
1fractually meansminmax(auto, 1fr). If a wide<pre>code block or data table sits inside a1frmain content column, the track can stretch wider than the viewport. Declaringminmax(0, 1fr)instead of bare1frguarantees code blocks stay safely scrollable inside their container.
6. Hands-On Grid Practice
Launch the snippet in the preview pane and add 5 course cards inside .course-grid. Switch auto-fit to auto-fill when only 2 cards exist to observe the spacing difference on wide viewports, then give the first card grid-column: span 2; inside a @media (min-width: 768px) query to build a classic editorial hero-plus-cards layout.
.course-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
gap: 24px;
}
.dashboard-shell {
display: grid;
grid-template-columns: 260px 1fr;
gap: 28px;
}