CSS grid wrap

There is no wrap property in grid. Columns wrap when you define them with repeat(auto-fit, minmax(...)), which lets the track count respond to the container width.

CSS grid wrap is not a property. Grid items move to the next row when the track definition produces fewer columns than there are items.

The rule that does the work is repeat(auto-fit, minmax(...)) in grid-template-columns. Nothing else is needed for a responsive card layout.

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}
A card grid at full window width, four columns across one row.
A card grid at full window width, four columns across one row.

Read it right to left. Each track is at least 220px and at most one equal share. The browser fits as many as it can, and the rest go to the next row.

Why there is no wrap property

Flex lays items along a single line, so flex-wrap: wrap gives permission to start another. Grid starts from a defined structure of rows and columns.

An item that does not fit the defined columns creates an implicit row instead. The wrapping is already there; what you control is how many columns exist.

Question Flex Grid
How do items move to a new line flex-wrap: wrap More items than columns
How many per line Whatever fits The track definition
Columns line up between rows No Yes
Last row alignment Often ragged Follows the same tracks

The third row is why grid is the better choice for card layouts. In a wrapped flex container the second row rarely aligns with the first.

auto-fit against auto-fill

Both keywords create as many tracks as the container allows. They differ only when there are fewer items than tracks.

/* three items in a container wide enough for five */
.a { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.b { grid-template-columns: repeat(auto-fit,  minmax(200px, 1fr)); }
  • auto-fill keeps the two empty tracks. The three items stay 200px wide, and empty space sits at the end of the row.
  • auto-fit collapses the empty tracks to zero width. The three items stretch across the whole row.
Two grids with three items each, one using auto-fill and one using auto-fit, showing different widths.
Two grids with three items each, one using auto-fill and one using auto-fit, showing different widths.

Pick auto-fit when items should always fill the row. Pick auto-fill when a consistent card width matters more than a flush edge, for example an image gallery.

Stopping overflow

Three things cause a grid to overflow instead of wrapping.

  1. The minimum is larger than the container. minmax(320px, 1fr) in a 300px column cannot shrink. Write minmax(min(320px, 100%), 1fr) so the minimum yields on narrow screens.
  2. An item refuses to shrink. Grid items default to min-width: auto, which respects content. A long URL or a wide table forces the track open. Set min-width: 0 on the item.
  3. Padding counted on top of the width. Add box-sizing: border-box, described in box sizing.
.cards { grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); }
.cards > * { min-width: 0; }

Those two lines resolve the large majority of reported wrapping failures.

Controlling the last row

A row with fewer items than tracks stretches under auto-fit. If that looks wrong, two options exist.

/* keep natural width, pack to the start */
.cards {
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  justify-content: start;
}

Or cap the individual item width with max-width so a lone card on the final row does not span the container.

Rows created by wrapping

Tracks the browser adds because items ran out of columns are implicit rows. They size to their content by default, which means a row with one tall card makes every card in that row tall.

grid-auto-rows sets their height explicitly.

.cards {
  grid-auto-rows: minmax(160px, auto);
}

That reads as a minimum of 160px, growing if the content needs more. It stops a row of short cards from collapsing while still letting a long one expand.

To stop the stretching entirely, align the items instead of the tracks.

.cards { align-items: start; }

Now each card is as tall as its own content and the row is as tall as the tallest. Which you want depends on whether the cards read as a set or as individual items.

Gap counts against the available width

A common miscalculation: with a 16px gap and a 240px minimum, four columns need 960px of tracks plus 48px of gaps, so 1008px. The browser accounts for this automatically, but it explains why a container you expected to hold four columns holds three.

Container width Min 240px, gap 16px Columns
700px 240 + 16 + 240 = 496 fits, third needs 752 2
800px Third column needs 752 3
1100px Fourth needs 1008 4
1300px Fifth needs 1264 5

If the break points land in the wrong place, adjust the minimum rather than adding media queries. Every 20px of minimum moves the whole ladder.

Wrapping text inside the cells

A grid that wraps correctly can still overflow because of what is inside it. Long unbroken strings, a URL or a serial number, force a track wider than its stated maximum.

.cards > * {
  min-width: 0;
  overflow-wrap: anywhere;
}

min-width: 0 overrides the automatic minimum that respects content. overflow-wrap: anywhere lets the string break mid word rather than pushing the track open.

Tables inside grid cells need the same treatment plus table-layout: fixed, otherwise the table's own sizing algorithm wins over the track maximum.

Wrapping in the other direction

Items can also be told to span more than one track, which changes where wrapping occurs.

.feature { grid-column: span 2; }

If the container is only one track wide, span 2 would overflow. Guard it with grid-column: span 2 inside a media query, or use min(2, ...) style logic by scoping the rule.

Checking the layout at several widths

The same card grid in a narrow window, wrapped to a single column.
The same card grid in a narrow window, wrapped to a single column.

Resize the window and watch where the break points land. The useful widths to check are roughly 380px, 700px and 1200px.

Open the file in the HTML file opener to confirm the layout holds outside your editor, then paste it into a document and share it as a link. A reader on a phone sees the wrapped version without you exporting anything.

For the spacing between wrapped rows see CSS grid row gap. For the wider property set see CSS grid, and flexbox for the cases where a single line is what you actually want.

Questions people ask

Does CSS grid have a flex-wrap equivalent?

No. flex-wrap exists because flex items sit on a single line by default. Grid items are placed into a defined track structure, so wrapping is controlled by how many tracks you define. repeat(auto-fit, minmax(220px, 1fr)) is the usual answer.

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

Both create as many tracks as fit. auto-fill keeps the empty tracks, so remaining items stay at their natural width and a gap sits on the right. auto-fit collapses the empty tracks to zero, so the existing items stretch to fill the row.

Why do my grid items overflow instead of wrapping?

Usually minmax has a minimum larger than the container, or an item has content that will not shrink, such as a long unbroken string. Use minmax(min(220px, 100%), 1fr) and add min-width: 0 to the items to let them shrink.

Do I still need media queries with auto-fit?

Often not for the column count, since auto-fit responds to the container width on its own. Media queries are still useful for changing gap, font size, or switching layout structure entirely at small widths.

Keep reading