CSS Grid: The Layout System That Changed Everything

I spent way too long fighting with floats. Then Flexbox came along and I thought, okay, this is it, we have solved CSS layout. And for one-dimensional stuff, Flexbox really is great. But the moment you need to control both rows and columns at the same time, Flexbox starts to feel like you are building a house with duct tape. You can make it work, but it is not the right tool.
CSS Grid is the right tool. It has been supported in all major browsers since 2017, but I only started using it seriously this year. I wish I had picked it up sooner.
The Basics
Grid works by defining a container and then placing items into a two-dimensional grid of rows and columns. The syntax is surprisingly readable once you get the hang of it.
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: auto 1fr auto;
gap: 16px;
}
The fr unit is my favorite part. It stands for "fraction of available space." So 1fr 2fr 1fr gives you three columns where the middle one is twice as wide as the sides. No percentages, no calc(), no guessing. The browser does the math for you.
The gap property replaces all those margin hacks we used to do. One line, consistent spacing, no collapsing margin surprises.
Named Grid Areas
This is where Grid really starts to feel like a superpower. You can name areas of your grid and place items into them by name.
.layout {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
gap: 16px;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
Reading that CSS, you can literally see the layout. Header spans the top, three columns in the middle, footer spans the bottom. Try getting that clarity with floats.
Responsive Without Media Queries
One of the things that surprised me the most is how much responsive behavior you can get without writing a single media query. The auto-fill and auto-fit keywords combined with minmax() do most of the heavy lifting.
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
}
This creates as many columns as will fit, with each column being at least 280px wide. On a large screen, you might get four columns. On a tablet, two. On a phone, one. The browser figures it out. No breakpoints needed.
The difference between auto-fill and auto-fit is subtle but important. auto-fill creates empty tracks when there is leftover space. auto-fit collapses those empty tracks, so existing items stretch to fill the row. For most card layouts, auto-fill is what you want.
Building a Dashboard Layout
I recently rebuilt a dashboard layout using Grid, and the difference in code complexity was night and day. The old version used nested Flexbox containers with percentage widths, media queries at three breakpoints, and a lot of calc() expressions. The Grid version was about a third of the CSS.
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto auto 1fr;
gap: 16px;
padding: 16px;
}
.stat-card { }
.chart-wide {
grid-column: span 2;
}
.chart-full {
grid-column: 1 / -1;
}
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr;
}
.chart-wide {
grid-column: span 1;
}
}
The span 2 syntax lets a card take up two columns. The 1 / -1 syntax means "start at the first line and end at the last line," which makes an item span the full width regardless of how many columns exist. One media query handles the mobile collapse.
Grid vs Flexbox
I do not think Grid replaces Flexbox. They solve different problems, and I use both constantly.
Flexbox is one-dimensional. It is perfect for navbars, button groups, centering a single element, or distributing items along a single axis. When I need to arrange items in a row or a column and let them wrap naturally, Flexbox is still my first choice.
Grid is two-dimensional. It is the right tool when I am thinking about rows and columns simultaneously. Page layouts, card grids, dashboards, form layouts. Anything where the alignment of both axes matters.
A good rule of thumb: if I am working from the content out (letting items determine the layout), I reach for Flexbox. If I am working from the layout in (defining a structure and placing items into it), I reach for Grid.
Things I Got Wrong
I will admit I made some mistakes when I first started. I tried to use Grid for everything, including simple single-row layouts that Flexbox handles perfectly. I also over-complicated things by explicitly placing every item with grid-row and grid-column when the auto-placement algorithm would have done the right thing by default.
The auto-placement is smarter than I expected. If you just put items inside a grid container, they flow into cells automatically, left to right, top to bottom. You only need explicit placement when the default order is wrong.
My other mistake was not using minmax() enough. Fixed column widths break on small screens. Using minmax(0, 1fr) instead of just 1fr can also prevent content from overflowing its grid track, which is a gotcha that tripped me up more than once.
Where I Am Now
Every new layout I build starts with Grid. The mental model is so much cleaner: define your grid, place your items, done. The CSS is shorter, more readable, and easier to maintain. I genuinely enjoy writing layout CSS now, which is something I never thought I would say.
If you have been putting off learning Grid because Flexbox works "well enough," I would encourage you to try it on your next project. Start with a simple card grid using auto-fill and minmax(). Once you see how little code it takes, you will not want to go back either.