CSS Grid Explained: A Visual Guide with Examples

CSS Grid Explained: A Visual Guide with Examples

CSS Grid is the layout system built for two directions at once. You describe the rows and columns on the parent, then place the children into them. Page layouts, card galleries and dashboards that once took pages of CSS now take a few lines.

This guide explains Grid from the first line of code to full page layouts. Every example opens in a live playground, so you can change the values and see what happens.

Open the CSS Grid playground See the grid lines, change the tracks and copy the CSS.

The short version

PropertyGoes onWhat it does
display: gridParentTurns on Grid for the direct children
grid-template-columnsParentSets the number and size of the columns
grid-template-rowsParentSets the number and size of the rows
gapParentSets the space between tracks
grid-template-areasParentDraws the layout using names
grid-columnChildSets where a child starts and ends across
grid-rowChildSets where a child starts and ends down
grid-areaChildPuts a child into a named area

Your first grid

Three lines of CSS give you a complete grid:

CSS: a basic grid
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
HTML
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
</div>

That makes three equal columns with a 12px gap. The six children fill the cells in order, left to right, and start a new row when the columns run out. You did not need to create the rows, because Grid adds them as needed. Rows made this way are called implicit.

display: grid only affects the direct children of the element. A child's own children are not part of the grid.

Tracks, cells and lines

A grid of six coloured boxes in three columns and two rows, with red dashed lines numbered 1 to 4 across the top and 1 to 3 down the side
A grid with 3 columns has 4 column lines, and 2 rows have 3 row lines.

Four words make everything else in Grid easier to follow:

The numbers are on the lines, not the columns. This is the part that catches most people out. A three-column grid has four column lines, so the last line is 4, not 3. The playground draws these numbers on every grid for you.

The fr unit: share the free space

Three columns: a fixed 200 pixel column on the left, then a narrow column and a column twice as wide
In 200px 1fr 2fr, the first column is fixed and the rest is shared in the ratio 1:2.
CSS: fixed and flexible columns
.grid {
  display: grid;
  grid-template-columns: 200px 1fr 2fr;
}

fr means a fraction of the free space. The browser works it out in three steps:

  1. It takes the fixed sizes and gaps away from the total width.
  2. It adds up the fr values. Here 1 + 2 makes 3 shares.
  3. It divides what is left into those shares.

In a 1,000px grid, 800px is left after the 200px column. That makes each share about 267px, so the columns come to 200px, 267px and 533px.

This is why fr is better than percentages. 33.33% columns plus a gap are wider than the grid and overflow it, while 1fr takes the gap out first. Try it in the fr units example.

repeat() and minmax()

repeat() saves you from typing the same size many times:

CSS: repeat
grid-template-columns: repeat(4, 1fr);          /* same as 1fr 1fr 1fr 1fr */
grid-template-columns: 80px repeat(3, 1fr);     /* mixed with other sizes */
grid-template-columns: repeat(2, 100px 1fr);    /* 100px 1fr 100px 1fr */

minmax() sets a smallest and a largest size for a track. The track grows and shrinks between the two:

CSS: minmax
grid-template-columns: minmax(200px, 300px) 1fr;  /* sidebar between 200 and 300px */
grid-template-rows: minmax(100px, auto);          /* at least 100px, taller if needed */

Responsive cards with no media queries

Put those two together and you get the most useful single line in CSS Grid:

CSS: responsive card grid
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 16px;
}
Seven coloured cards in rows of three, with the seventh card alone on a third row and two empty cells beside it
The browser fits as many columns as it can, then wraps the rest onto a new row.

Read it as: make as many columns as fit, each at least 250px wide, and share out any spare space. On a phone that gives one column, and on a wide screen it might give four. No media query is needed. Change the browser width with the responsive cards example open and watch the line numbers change.

auto-fit vs auto-fill

The two keywords only behave differently when you have fewer items than columns:

Make an item span several cells

A photo gallery grid: item 1 is a large square covering two columns and two rows, item 6 is two columns wide, and the other items fill the single cells around them
Item 1 uses span 2 in both directions, and the other items flow around it.
CSS: spanning
.big {
  grid-column: span 2;   /* two columns wide */
  grid-row: span 2;      /* two rows tall */
}

.banner {
  grid-column: 1 / -1;   /* from the first line to the last line */
}

.placed {
  grid-column: 2 / 4;    /* from line 2 to line 4 */
  grid-row: 1 / 3;       /* from line 1 to line 3 */
}

The value before the slash is the start line and the value after it is the end line. span 2 means “take up two tracks from wherever you land”, which is handy when you don't care about the exact position. Negative numbers count from the end, so -1 is the last line.

This is how you build a magazine or photo layout. Open the photo gallery example, click any item and give it a span.

When a large item leaves a hole, grid-auto-flow: row dense tells Grid to go back and fill it with a later, smaller item. The visual order then differs from the HTML order, so don't use it where the reading order matters.

grid-template-areas: draw your layout

A page layout grid with a full-width header, a sidebar beside a large main area, and a full-width footer
The areas in the CSS look just like the finished page.
CSS: a full page layout
.page {
  display: grid;
  grid-template-columns: 160px 1fr;
  grid-template-rows: 64px 1fr 56px;
  grid-template-areas:
    "header  header"
    "sidebar main"
    "footer  footer";
  gap: 8px;
  min-height: 100vh;
}

.page header { grid-area: header; }
.page aside  { grid-area: sidebar; }
.page main   { grid-area: main; }
.page footer { grid-area: footer; }

Each quoted string is a row, and each word is a cell. Repeat a word to stretch that area across cells. It works like a small drawing of the page, and many developers find it the easiest way to read a layout. Use a dot (.) for an empty cell.

Areas also make responsive layouts simple. On a small screen, redraw the map as one column and leave the HTML alone:

CSS: a different layout on phones
@media (max-width: 700px) {
  .page {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    grid-template-areas:
      "header"
      "main"
      "sidebar"
      "footer";
  }
}

Each area must be a single rectangle. An L shape is invalid, and the browser then ignores the whole grid-template-areas value. You can test this in the page layout example: the box turns red until the value is valid again.

Alignment: justify and align

A large empty grid area with one small purple box exactly in the centre
justify-items and align-items both set to center put a child in the exact middle.

Grid has one simple naming rule: justify works across (the row direction) and align works down (the column direction).

PropertyMovesGoes on
justify-itemsAll items across, inside their cellsParent
align-itemsAll items down, inside their cellsParent
justify-contentThe whole grid across, inside the parentParent
align-contentThe whole grid down, inside the parentParent
justify-selfOne item acrossChild
align-selfOne item downChild

place-items sets align-items and justify-items together, which gives you the shortest way to center anything in CSS:

CSS: perfect centering
.parent {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

Without a height on the parent, there is no spare space to center in. See the perfect center example, or read 7 ways to center a div for the other methods.

Items stretch to fill their cells by default. This is why all the cards in a row come out the same height, with no extra code.

Rows you didn't define

When items overflow the rows you wrote, Grid creates new ones and sizes them to their content. Use grid-auto-rows to control them, which is useful when you don't know how many items there will be:

CSS: size for automatic rows
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(150px, auto);   /* every new row is at least 150px */
}

Grid vs Flexbox: which should you use?

FlexboxGrid
DirectionsOne at a timeTwo at once
Driven byThe content's sizeThe layout you define
Best forNavbars, button rows, centering a few itemsPage layouts, card grids, dashboards
Items line up across rowsNo, each row is separateYes, always

A good rule: if you want things to line up in both directions, use Grid. If you just need a line of things, use Flexbox. Most real pages use both, such as Grid for the page and Flexbox for the header inside it. Our Flexbox guide covers the other half.

Common mistakes

Try it in the playground

The CSS Grid playground: controls on the left for columns, rows, areas and gap, example buttons at the top, a live photo gallery grid with numbered lines in the middle, and settings for the selected item on the right
Type your own tracks, click an item to place it, and copy the CSS.

In the CSS Grid playground you can type any value into the columns and rows, and invalid values are flagged straight away. Try these:

Share your layout

Built something you want feedback on? Paste it into the free code sharing tool, or share a screenshot as a link with sshot.online. No account needed.

Frequently asked questions

What is the difference between CSS Grid and Flexbox?

Flexbox works in one direction at a time, either a row or a column. Grid works in two directions at once, so you control rows and columns together. Use Flexbox for a line of things, like a navbar, and Grid for a whole layout or a set of cards that must line up in both directions.

What does 1fr mean in CSS Grid?

fr stands for fraction. 1fr means one share of the free space left in the grid after fixed sizes and gaps are taken out. In 200px 1fr 2fr, the first column gets 200px and the last column gets twice the width of the middle one.

What is the difference between auto-fit and auto-fill?

Both create as many columns as fit. auto-fill keeps the empty columns, so a few items stay at their small size. auto-fit collapses the empty columns, so the items stretch to fill the row. You only see a difference when there are fewer items than columns.

How do I make a CSS Grid responsive without media queries?

Use grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)). The browser fits as many 250px columns as it can, shares out the spare space, and wraps the rest onto new rows.

Why does grid-column: 1 / -1 not span the full width?

Negative line numbers only count lines in the explicit grid, which is the part you defined with grid-template-columns. If your columns are created automatically or your grid has no template, -1 does not point to the end you expect. Define the columns first.

Is CSS Grid supported in all browsers?

Yes. All current browsers have supported CSS Grid since 2017, so you can use it without a fallback. Only very old browsers such as Internet Explorer lack the modern version.

Related articles

← All guides