CSSAuto Placement & grid-auto-flow

Auto Placement & grid-auto-flow

Not every grid item needs an explicit grid-column or grid-row. Any item you don't place manually is handled by the grid's auto-placement algorithm, and grid-auto-flow controls exactly how that algorithm walks through the available cells.

How Auto-Placement Works

By default, unplaced items are dropped into the grid one at a time, filling the first available cell in the current row before moving to the next row — much like text wrapping. Items with explicit placement are laid down first; auto-placed items then fill in around them, skipping any cell that's already occupied.

CSS
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  /* grid-auto-flow: row; -- this is the default, shown for clarity */
}
row vs column vs dense

Value

Behavior

row (default)

Fills each row left-to-right, then wraps to the next row when the current one is full.

column

Fills each column top-to-bottom instead, wrapping to the next column. Requires grid-template-rows to define a finite number of rows, or items will just spill into one very tall implicit column.

dense

Combines with row or column (row dense / column dense) to backfill earlier gaps left by larger items, instead of always moving forward.

CSS
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-flow: column;
  grid-template-rows: repeat(2, 100px);
}
Seeing dense in Action

dense matters most when items of different sizes are mixed together. Without it, a large item can leave an awkward empty gap behind it that never gets filled, because the algorithm only ever moves forward:

CSS
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  grid-auto-flow: row dense; /* try removing "dense" to see the gap appear */
}

.wide { grid-column: span 2; }
.tall { grid-row: span 2; }

HTML
<div class="grid">
  <div class="wide">1 (spans 2 columns)</div>
  <div>2</div>
  <div>3</div>
  <div class="tall">4 (spans 2 rows)</div>
  <div>5</div>
  <div>6</div>
</div>

Without dense, item 2 lands after item 1's wide span leaves a 1-column gap in the same row that never gets backfilled — the algorithm keeps moving strictly forward. With dense, the browser looks back and slots smaller items into any earlier gap they fit, producing a visually tighter, gap-free grid.

dense can reorder visual content ahead of DOM order
`dense` is purely visual — it does not change the DOM or the tab/ reading order, only where each item paints. For content where visual order matters for comprehension (not just decorative tiles), test with a screen reader or keyboard-only navigation, since the visual and logical order can now diverge.
Auto-Placement Creates Implicit Tracks

When there are more auto-placed items than the explicit grid has room for, the grid grows extra rows (or columns, with grid-auto-flow: column) automatically. Those extra tracks are sized by grid-auto-rows / grid-auto-columns — see Implicit vs Explicit Grid for the full picture of how the two systems interact.

  • grid-auto-flow: row is the right default for most content-driven grids — items simply wrap like text.

  • Use column only when you have a fixed number of rows and want items filling vertically first, which is a less common layout need.

  • Reach for dense when item sizes vary and you want a Pinterest-style packed layout — but weigh the accessibility trade-off first.

Next
Understand exactly how many implicit tracks get created and how they're sized: [Implicit vs Explicit Grid](/css/implicit-explicit-grid).