For most of CSS history, laying out a page was a small nightmare. We hacked it together with float, position, and negative margins. Then Flexbox arrived and made one-dimensional layouts (rows or columns) much easier. CSS Grid went further: it made two-dimensional layouts — rows and columns at the same time — a first-class feature of the language.
If you can describe your layout as a grid of boxes (which describes almost every modern interface), CSS Grid is the right tool. This article assumes you know basic CSS — selectors, the box model, and how to link a stylesheet. If you need a refresher, our CSS for Beginners article covers all of that.
Why Grid exists
Imagine a typical blog page: a header across the top, a sidebar on the left, the article in the middle, and a footer at the bottom. Without Grid, you would float the sidebar left, set widths on the article, and pray. With Grid, you describe the entire layout in three lines of CSS and let the browser figure it out.
Grid is also fantastically good at responsive design. The same layout that shows a sidebar on a desktop can collapse into a single column on a phone with two extra lines of CSS. Once you internalise the basics, you will find yourself reaching for Grid constantly.
The mental model
When you turn on CSS Grid for an element, that element becomes a grid container. Its direct children become grid items. The container has a defined number of rows and columns (which can be implicit when you do not specify them). Every item lives in a cell of the grid.
Here is the absolute minimum you need to get started:
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
}
That single rule turns the container into a three-column grid with equal-width columns and a 1rem gap between every cell. The fr unit means "fraction of the available space." 1fr 1fr 1fr means "three equal columns."
Defining columns and rows
The most flexible way to define columns is with grid-template-columns and a list of sizes. Sizes can be fixed (200px), flexible (1fr), or based on content (minmax(200px, 1fr)). The minmax function is the magic ingredient for responsive design:
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
}
That single rule creates as many 250-pixel-or-larger columns as will fit in the container. On a phone you might get one column, on a tablet two, on a desktop four. No media queries needed. This is the canonical "responsive card grid" pattern and you will use it forever.
You can also define rows with grid-template-rows, and a fully explicit grid with both. Most of the time, however, you only need to set up the columns and let the rows grow naturally.
Placing items
By default, items flow into the grid one cell at a time, in source order. That is fine for uniform grids (a list of cards, a photo gallery). For asymmetric layouts (a sidebar, a hero with a small panel), you can place specific items with grid-column and grid-row:
.sidebar { grid-column: 1; grid-row: 2 / 4; }
.main { grid-column: 2 / -1; grid-row: 2; }
The values use the grid lines as their reference. grid-column: 1 means "start at line 1, span 1 column." grid-column: 2 / -1 means "start at line 2, end at the last line." The negative index counts from the end, which is wonderfully convenient.
You can also use the shorthand grid-area with named areas, which is much more readable for complex layouts. We will look at that in a moment.
Named areas: the readable way to lay out
When a layout has well-defined regions — header, sidebar, main, footer — named areas are a delight. Define them once on the container, then reference them by name on each child:
.layout {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
gap: 1rem;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
You can see the layout shape right there in the CSS. The grid template literally draws a picture with strings. To make the sidebar disappear on a phone:
@media (max-width: 640px) {
.layout {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"footer";
}
.sidebar { display: none; }
}
Same HTML, two layouts, six lines of CSS. The MDN Grid reference is the canonical source when you need to look up edge cases.
Alignment inside cells
By default, grid items stretch to fill their cell. That is usually what you want for text content. When you want different alignment, use justify-items (horizontal), align-items (vertical), or the shorthand place-items on the container. For a single item, override with align-self and justify-self:
.card {
justify-self: center;
align-self: center;
}
The values are start, center, end, and stretch. The trickiest part is remembering which axis is which: in a left-to-right language, justify-* is horizontal and align-* is vertical.
A full example: a responsive photo gallery
Let us build something useful. Here is a photo gallery that responds to the screen size without any media queries:
<div>
<img src="1.jpg"> <img src="2.jpg"> <img src="3.jpg">
<img src="4.jpg"> <img src="5.jpg"> <img src="6.jpg">
</div>
<style>
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1rem;
padding: 1rem;
}
.gallery img {
width: 100%;
aspect-ratio: 4 / 3;
object-fit: cover;
border-radius: 12px;
}
</style>
That is the whole thing. The auto-fit with minmax trick does the heavy lifting — the gallery shows as many columns as will fit, with each image at least 220 pixels wide. Resize the window and watch the layout reflow.
Common pitfalls
- Forgetting
display: gridon the container. Without it, none of the Grid properties apply and nothing happens. - Confusing
frwith%.frdivides the remaining space after fixed sizes.%is relative to the parent's content box and can produce overflow. Usefrfor almost everything. - Putting Grid on a parent whose children are not direct. Only direct children become grid items. If you have an extra
<div>wrapper around your items, Grid is operating on the wrapper, not the items. - Using
grid-gap(deprecated). Usegapnow. The old property still works but the new one is shorter and clearer. - Expecting Grid to handle margins. Grid handles gaps. Use the
gapproperty instead of margin-based spacing inside the container.
Grid versus Flexbox
Both are great. Use Flexbox for one-dimensional layouts (a row of buttons, a centred box, a navigation bar). Use Grid for two-dimensional layouts (a page, a card grid, a calendar). When in doubt, start with Grid — it can do everything Flexbox can do, plus more.
Going one step further: subgrid
CSS Grid has a feature called subgrid that lets a grid item's children align to the parent grid. Imagine a card grid where each card has a title, an image, and a description, and you want every title to be the same height across the row, and every description to start at the same height too. Without subgrid, you cannot do this cleanly — each card is its own little world.
Subgrid fixes that. With grid-template-rows: subgrid on the card, its rows inherit the parent's row sizing. Now titles align across cards. It is supported in every modern browser as of 2026, and it is the kind of feature that, once you know it, you cannot believe you lived without.
Another modern feature is the aspect-ratio property, which you saw in the gallery example above. It lets you write aspect-ratio: 4 / 3 instead of the old padding-bottom hack. The grid layout plus aspect-ratio plus object-fit: cover is the modern, lazy way to build a perfectly aligned image gallery in three lines of CSS.
Further reading
CSS Grid has been the canonical layout tool since 2017. These are the docs the Mangobaz team points clients and junior devs at.
- MDN: CSS Grid Layout — The reference we trust most for property-by-property documentation.
- CSS-Tricks: A Complete Guide to CSS Grid — A visual companion that makes Grid intuitive when you are still learning.
- W3C: CSS Grid Layout specification — The actual specification — useful when MDN is not precise enough.
FAQ
Can I use Grid today?
Yes. Grid has been supported in every modern browser since 2017. There is no longer any reason to avoid it. The MDN basic concepts page is the best place to start.
What is the difference between Grid and Flexbox?
Grid is two-dimensional (rows and columns at once). Flexbox is one-dimensional (a row or a column). Grid excels at page-level layouts and card grids; Flexbox excels at small component-level arrangements.
How do I centre something with Grid?
Place it in a single cell and use place-items: center on the container, or justify-self: center; align-self: center; on the item. Both work; pick whichever feels natural.
How do I make a grid item span multiple columns?
Use grid-column: span 2. You can also write it as grid-column: 1 / 3 to span from line 1 to line 3. For named areas, just name the same area multiple times in the template.
Can I animate grid layouts?
You can animate properties like grid-template-columns in modern browsers, but it has historically been janky. Use a combination of regular CSS transitions on individual items and the FLIP technique for complex layout animations. For most cases, prefer a simpler animation strategy.
How do I make items of different sizes align?
Use named grid areas for the major regions (header, sidebar, footer) and let individual cards use the default flow with grid-column: span 2 for the ones that should be twice as wide. Named areas and spans work together without conflict.
What about masonry layouts?
True masonry (Pinterest-style) is not part of CSS Grid yet. There is a grid-template-rows: masonry value in the spec but browser support is still incomplete. For now, use a JavaScript library like Masonry.js or a CSS columns trick.
Homework
Take the favourite.html you have been building. Add a section with three facts about your favourite thing, each presented in a card. Use CSS Grid to lay them out in three columns on a desktop and a single column on a phone. Bonus points if you use the auto-fit minmax trick so there is no media query.
Then add a simple page layout using named grid areas: header on top, footer at the bottom, sidebar on the left, main content on the right. Use a media query to collapse the sidebar into a top bar on small screens. If you get stuck, copy the layout snippet from earlier in this article and modify it for your page.