Mastering CSS Grid
Sat Mar 15 · 3 min read
Why CSS Grid changed everything
Before Grid, building layouts in CSS meant fighting floats, clearfixes, and table hacks. Flexbox helped, but it's one-dimensional — it handles rows or columns, not both at once. Grid is two-dimensional and gives you real control over your layouts without extra markup.
Once it clicked for me, I stopped reaching for layout libraries entirely.
The mental model
Think of CSS Grid as drawing a table on your page. You define the rows and columns, then place items wherever you want inside that grid.
.container {
display: grid;
grid-template-columns: 200px 1fr 1fr;
grid-template-rows: auto;
gap: 24px;
}This creates a three-column grid: one fixed 200px column and two flexible columns that share the remaining space equally.
The fr unit
fr stands for "fraction of available space." It's the most useful unit in Grid.
grid-template-columns: 1fr 2fr 1fr;This splits the container into four equal parts, giving the middle column two of them. No math, no percentages, no calc().
Placing items explicitly
By default, Grid auto-places items left to right, top to bottom. But you can place items exactly where you want.
.header {
grid-column: 1 / -1; /* span all columns */
}
.sidebar {
grid-column: 1 / 2;
grid-row: 2 / 4;
}
.main {
grid-column: 2 / -1;
grid-row: 2 / 3;
}The -1 shorthand means "the last line" — so 1 / -1 always spans the full width regardless of how many columns you have.
Named template areas
For complex layouts, named areas are more readable than line numbers.
.layout {
display: grid;
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
grid-template-columns: 200px 1fr 1fr;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }This reads like a diagram of your layout. It's immediately obvious what goes where.
Responsive grids without media queries
auto-fill and auto-fit with minmax() let you build responsive grids with zero media queries.
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
}This creates as many columns as fit, each at least 250px wide. On a wide screen you get four columns. On mobile you get one. No breakpoints needed.
auto-fill vs auto-fit
These are subtly different and the difference matters.
auto-fillkeeps empty columns, preserving the grid structureauto-fitcollapses empty columns so items stretch to fill the space
For card grids where you want items to fill the row, use auto-fit. For grids where position matters even with missing items, use auto-fill.
Alignment
Grid gives you fine-grained control over alignment in both axes.
.container {
justify-items: center; /* horizontal alignment of items */
align-items: center; /* vertical alignment of items */
justify-content: space-between; /* horizontal alignment of the grid */
align-content: start; /* vertical alignment of the grid */
}You can also override alignment per item with justify-self and align-self.
Subgrid
Subgrid is one of the newer features and it's genuinely useful. It lets a child grid align to its parent's grid lines.
.parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.child {
grid-column: span 3;
display: grid;
grid-template-columns: subgrid;
}This solves the classic problem of aligning content inside cards to columns defined by a parent grid.
What I actually use day to day
In practice, most of my Grid usage comes down to three patterns:
Two-column layout with sidebar
grid-template-columns: 240px 1fr;Responsive card grid
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));Full-page layout
grid-template-rows: auto 1fr auto; /* header, main, footer */
min-height: 100vh;Closing thoughts
CSS Grid is one of those tools that feels complex until it suddenly doesn't. The key is learning the mental model — rows, columns, and line numbers — rather than memorizing every property.
Start with repeat(auto-fit, minmax()) for responsive grids and explicit grid-column placement for custom layouts. The rest follows naturally.