CSS Grid Auto Placement Algorithm

May 28, 20265 min read

What Is Grid Auto Placement?

When you define a grid container but do not explicitly place every item using grid-column or grid-row, the browser must decide where those unplaced items go. The auto placement algorithm handles this — it fills empty cells following rules you control via grid-auto-flow.

Understanding this algorithm helps you predict layout behavior instead of guessing and tweaking blindly.

The Three Modes of grid-auto-flow

ValueBehaviorUse Case
row (default)Fill rows left to right, then move to next rowStandard card grids, lists
columnFill columns top to bottom, then move to next columnVertical feeds, sidebar items
denseBackfill earlier gaps left by spanning itemsMasonry-like layouts, mixed-size grids

You can combine dense with row or column:

.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-flow: row dense;
}

How the Algorithm Works — Step by Step

Step 1: Place Items with Explicit Positions

Items that specify grid-column or grid-row get placed first. The algorithm skips these and reserves their cells.

.featured {
  grid-column: 1 / 3; /* spans 2 columns */
}

Step 2: Determine the Auto-Flow Direction

The algorithm picks the next available cell based on grid-auto-flow:

  • row: Move right across columns, then down to next row
  • column: Move down across rows, then right to next column

Step 3: Place Remaining Items in Order

Items without explicit placement fill cells in DOM order. If an item spans multiple tracks (span 2), the algorithm searches for a contiguous block of empty cells large enough.

Step 4: Handle Dense Packing (if enabled)

With dense, after placing an item that spans multiple tracks, the algorithm goes back to check whether smaller items can fill gaps left behind. Without dense, those gaps stay empty.

The Spanning Problem

Spanning items create gaps. Consider a 4-column grid with grid-auto-flow: row:

[1-wide] [1-wide] [1-wide] [3-wide spanning]
                          ┌─────────────────┐
                          │    spans 3 cols  │
                          └─────────────────┘

The 3-wide item does not fit in the last column of row 1 (needs 3 consecutive empty cells), so it wraps to row 2. This leaves column 4 of row 1 empty — a gap.

Without dense: the gap persists. The next item starts at row 2, column 1.

With dense: the algorithm backfills. The next 1-wide item fills column 4 of row 1.

/* Without dense — gaps persist */
.grid { grid-auto-flow: row; }

/* With dense — gaps get filled */
.grid { grid-auto-flow: row dense; }

Practical Example: Magazine Layout

.magazine {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(200px, auto);
  grid-auto-flow: row dense;
  gap: 16px;
}

.hero {
  grid-column: span 2;
  grid-row: span 2;
}

.sidebar {
  grid-column: span 1;
  grid-row: span 2;
}

Without dense, the hero item (2×2) and sidebar item (1×2) would leave scattered gaps. With dense, smaller items slide into those gaps, creating a compact layout.

Dense Packing Trade-offs

Aspectrow (sparse)row dense
Visual gapsPossibleMinimized
DOM order preservedYesNo — smaller items may appear before larger ones in DOM
AccessibilityPredictable tab orderTab order may jump visually
PerformanceFaster algorithmSlightly slower (backfilling)

Important: dense reorders items visually but not in the DOM. Screen readers and keyboard navigation still follow DOM order. If visual order matters for accessibility, use explicit placement instead.

Auto Tracks and Implicit Grid

When items overflow the defined grid-template-columns or grid-template-rows, the browser creates implicit tracks. Control their size with:

.grid {
  grid-auto-rows: minmax(100px, auto);
  grid-auto-columns: 200px;
}

Without these, implicit tracks default to auto — sized to their content. This often creates uneven row heights in dynamic layouts.

Named Grid Lines and Auto Placement

If you define named lines, the algorithm can use them for automatic spanning:

.grid {
  grid-template-columns: [col-start] 1fr [col-end] repeat(3, 1fr);
}

.item {
  grid-column: col-start / span 2;
}

Named lines make auto placement more predictable because items reference specific tracks rather than numeric indexes that shift when you change column counts.

Key Takeaways

  • Grid auto placement fills unplaced items according to grid-auto-flow
  • Spanning items can leave gaps — dense backfills those gaps
  • Dense packing trades DOM order preservation for visual compactness
  • Always define grid-auto-rows when row count is dynamic
  • For accessible layouts, prefer explicit placement over dense reordering

Try It Yourself

Build and experiment with grid layouts using our CSS Grid Generator. Define columns, rows, and gaps visually — then copy the CSS into your project.