⊞CSS Grid Complete Guide

Dense Packing

When items span multiple tracks, gaps can appear in the grid. grid-auto-flow: dense tells the browser to backfill those holes with smaller items β€” potentially changing visual order.

grid-auto-flow: densegrid-auto-flow: row densegrid-auto-flow: column dense

1. The Problem: Gaps from Spanning Items

When a spanning item doesn't fit in the current row, it moves to the next row β€” leaving a hole. Without dense, these holes are never filled.

Live Demo
span 2
1
span 2
1
1
1
span 2
1
CSS
.container {
  grid-template-columns: repeat(3, 1fr);
  grid-auto-flow: row; /* default β€” no dense */
}
/* Gaps appear when span-2 items can't fit */
/* The empty spaces are never filled        */
πŸ’‘ Notice the holes (empty cells) that appear. These happen because the 'span 2' items skip to the next row when they don't fit in 1 remaining column.

2. grid-auto-flow: dense β€” Fill the Gaps

Adding 'dense' to grid-auto-flow tells the browser to look for earlier gaps and fill them with later items that fit. This changes visual order but eliminates empty space.

Live Demo
span 2
1
span 2
1
1
1
span 2
1
CSS
.container {
  grid-template-columns: repeat(3, 1fr);
  grid-auto-flow: row dense; /* dense fills gaps! */
}
/* Browser backtracks and fills gaps   */
/* Visual order may differ from source */
πŸ’‘ ⚠️ Dense packing changes visual order without changing DOM order. This can hurt accessibility (screen readers, keyboard navigation follow DOM order). Use with care.

3. Before & After Comparison

Side-by-side comparison of the same items with and without dense packing. Notice how dense eliminates the holes.

Live Demo
Without dense (holes visible)
span 2
2
3
span 2
5
6
span 2
With dense (holes filled)
span 2
2
3
span 2
5
6
span 2
CSS
/* Without dense: */
.no-dense {
  grid-auto-flow: row;       /* holes appear */
}

/* With dense: */
.with-dense {
  grid-auto-flow: row dense; /* gaps filled */
  /* or just: grid-auto-flow: dense */
}

4. column dense

Use column dense when your flow is set to column. Items fill the column axis first, then dense packing fills gaps in previous columns.

Live Demo
span 2
2
3
span 2
5
span 2
7
8
CSS
.container {
  grid-template-rows: repeat(4, 50px);
  grid-auto-flow: column dense; /* column + dense */
  grid-auto-columns: 1fr;
}

5. Gallery / Masonry-Like Layout

Dense packing really shines in gallery layouts where images have varying heights. Combine row spanning with dense to approximate masonry-style layouts.

Live Demo
tall wide
2
tall
4
wide
6
tall
big
9
10
11
wide
CSS
.gallery {
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 40px;       /* row unit */
  grid-auto-flow: dense;        /* fill gaps */
}
.big    { grid-column: span 2; grid-row: span 3; }
.wide   { grid-column: span 2; }
.tall   { grid-row: span 2; }
πŸ’‘ This is as close to CSS masonry as you can get without JavaScript. True masonry (random height filling) is a separate CSS spec proposal: grid-template-rows: masonry.