Not every grid needs each item placed by hand: as soon as a child has no explicit position through grid-column or grid-row, the grid has to decide on its own where to put it. grid-auto-flow controls exactly that automatic placement logic, the one applied by default to every item in a simple grid.
By default, that logic fills row by row, but grid-auto-flow lets you switch it to fill column by column instead, or to backfill gaps left by items already placed by hand.
Definition
grid-auto-flow sets the direction in which CSS Grid automatically places items that have no explicit position, along with how it fills empty cells. It is set on the container, not on the children, and has no effect on items explicitly positioned with grid-column and grid-row, which always keep priority over automatic placement.
The available values
| Value | Behavior |
|---|---|
row (default) | Fills a full row before moving to the next one |
column | Fills a full column before moving to the next one |
dense | Backfills empty cells left behind, even if it changes the visual order |
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: column;
}With grid-auto-flow: column, items with no explicit position line up column by column instead of row by row, which completely changes how an otherwise identical grid reads visually. This is useful for layouts that should read top to bottom before left to right, like a calendar or a list organized into vertical categories.
Implicit tracks: grid-auto-rows and grid-auto-columns
When an item overflows the explicitly defined rows or columns, the grid creates implicit tracks to hold it. grid-auto-rows and grid-auto-columns set the size of these automatically created tracks, exactly the way grid-template-columns sets the size of explicit columns.
.grid {
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 120px;
}Without grid-auto-rows, an implicit row takes a height that adjusts to its content, which can create rows of very uneven heights. Fixing it at 120px, for example, keeps the grid visually regular even as it grows beyond what was originally planned.
A concrete example with dense
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: dense;
}
.large-tile {
grid-column: span 2;
grid-row: span 2;
}In a gallery where some tiles span two columns and two rows, the default placement often leaves empty cells right after a large tile, until the grid reaches a fresh complete row. With grid-auto-flow: dense, the smaller tiles that follow backfill those gaps instead of waiting their turn in strict HTML order, giving a visually tighter mosaic.
The trap of dense and visual order
The dense value visually reorganizes items to backfill gaps left by items of different sizes, giving a more compact looking grid. But this reorganization only changes what is displayed, never the order of the HTML code.
dense. On a grid where reading order matters, like a news feed or a list of steps, dense can create an awkward gap between what you see and what the keyboard walks through.Frequently asked questions
grid-auto-flow apply to items positioned with grid-column?No, an item positioned explicitly always keeps that exact position. grid-auto-flow only concerns items that received no position at all, by deciding where to insert them among the cells still left free.
grid-auto-flow: row dense and grid-auto-flow: column dense?Both backfill gaps, but in different directions: row dense looks for gaps while moving row by row, while column dense looks for them while moving column by column. The visual result depends on the chosen direction just as much as on the dense value itself.
grid-auto-flow replace the order property used in Flexbox?No, they are two different mechanisms. order changes the visual order of one specific item, in both Flexbox and Grid, while grid-auto-flow only changes the automatic placement logic applied to items with no defined position. The two can actually be combined on the same grid.