In CSS Grid, when is grid-auto-flow: dense the right choice, and what cost do you accept by using it?
answer
- the cursor restarts for every item
- a cosmetic fix with a semantic price
- DOM order still owns focus and speech
- fine for photo walls, not for rankings
- not the same as staggered brick layout
basics
~20 sDense packing backfills the holes that spanning items leave, so use it only where item order carries no meaning — decorative or self-describing tiles. The cost is that visual order stops matching DOM order, while reading order and Tab order still follow the DOM.
solid answer
~40 s`grid-auto-flow: row dense` tells the placement algorithm to restart its search from the beginning of the grid for every auto-placed item instead of only moving forward, so a later narrow item can drop back into a hole an earlier wide item left. That produces a tightly packed layout, which is exactly what you want for a photo wall or a tag cloud where nothing depends on sequence. The cost is a real accessibility and usability defect when order does matter: the accessibility tree, the screen-reader reading order and the Tab sequence all follow DOM order, so a visually backfilled item is announced and focused somewhere else entirely. I use it for order-insensitive, ideally non-interactive content, and reach for adjusting track counts or reordering the markup when sequence carries meaning.
code
css · 11 lines.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: row dense;
gap: 8px;
}
.gallery .feature {
grid-column: span 2;
grid-row: span 2;
}go deeper
Know what the keyword does: adding dense to grid-auto-flow lets later items fill in gaps that earlier spanning items left, producing a tighter layout.
Explain the mechanism — the placement cursor restarts at the beginning of the grid for each item instead of only moving forward — and state that only the visual arrangement changes, not the document.
Demonstrate the judgment: name what still follows DOM order (speech, Tab, find-in-page), give the order-insensitive/self-describing/non-interactive test, and mention layout instability as items load.
Own it as a policy question. Decide where in a design system dense is permitted, what review evidence is required (keyboard walkthrough, order-insensitivity of the content type), and whether track counts should be chosen so the question never arises.
## What dense actually changes `grid-auto-flow` carries two things: a direction (`row` or `column`) and a packing mode. The packing mode is *sparse* unless you write the `dense` keyword, as in `grid-auto-flow: row dense` (or just `dense`, which implies row flow). In sparse packing, the placement cursor only moves forward, so a cell that was skipped is stranded. In dense packing, **the cursor is reset to the start of the grid for every auto-placed item**. Each item is offered the earliest empty area big enough for it, which means a narrow item that comes later in the DOM can drop back into a hole a wide item left behind. ```css .gallery { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-flow: row dense; } .gallery .feature { grid-column: span 2; grid-row: span 2; } ``` The result is a compact mosaic with no holes — the effect people are usually chasing when they say "masonry". Note that it is not the same thing: dense packing still uses the row and column tracks the grid defines, so items stay aligned to shared row boundaries. It removes holes; it does not stagger items into offset brick courses. ## The cost, stated precisely Dense packing changes **only the visual arrangement**. It does not touch the DOM, and everything derived from the DOM keeps the original sequence: - The **accessibility tree** and therefore screen-reader reading order. - **Sequential focus navigation** — the Tab key visits focusable descendants in DOM order. - **Find-in-page**, text selection, and copy order. So a card that appears second visually may be the ninth thing announced and the ninth thing focused. For a keyboard user, focus appears to jump around the page unpredictably; for a screen-reader user, the description of the layout no longer matches what a sighted colleague sees on the same screen. This is the same class of defect as flexbox's `order` property, and it maps onto well-known accessibility requirements: content must be presented in a meaningful sequence, and focus order must preserve meaning and operability. The important nuance is that this is a defect **only when order carries meaning**. A wall of unrelated product photos has no meaningful sequence to destroy. A ranked leaderboard, a numbered checkout flow, a chronological feed, or a list of form fields does. ## A usable decision rule Use `dense` when *all* of these hold: 1. The items are **order-insensitive** — shuffle them and nothing is lost. 2. Each item is **self-describing** — a user who lands on it out of sequence still understands it, without needing "the one above" for context. 3. The items are **not interactive**, or their interactivity is simple and self-contained, so an out-of-order focus jump does not strand the user mid-task. 4. The holes are actually visible and actually bother the design — dense costs nothing to add, but it also buys nothing if there are no holes to fill. If any of those fail, prefer the alternatives: change the track count so spans divide evenly, drop or shrink the span at problem breakpoints, or reorder the source itself so the visual order you want *is* the DOM order. ## Second-order effects to mention **Instability.** Because every item is offered the earliest fitting hole, dense layouts are sensitive to their input. Add one item, change one span, or let one card's content grow, and items can jump to different positions than before. In an incrementally loading list this reads as items shuffling on screen while the user is looking at them, which is worse than a hole. Sparse packing is stable in the sense that earlier placements never change when later items arrive. **Cost of the algorithm.** Dense placement does more searching, since the cursor restarts for each item. For realistic item counts this is not something you should optimise for — but on a grid with thousands of auto-placed items it stops being free. **It does not reorder anything you placed.** Explicitly positioned items are placed before auto-placement runs; dense only affects the items the algorithm is choosing positions for. ## How to answer this in an interview Lead with the mechanism in one sentence (cursor restarts, so later items backfill earlier holes), then immediately name the divergence between visual order and DOM order and what depends on DOM order. Finishing with the decision rule — order-insensitive, self-describing, ideally non-interactive — is what separates "I know the keyword" from "I have shipped this and been bitten by it".
- Which user-facing behaviours still follow DOM order when dense packing is on?Everything derived from the document rather than the layout: the accessibility tree and screen-reader reading order, sequential focus navigation with the Tab key, find-in-page, and text selection or copy order. `dense` changes only which grid area each item is painted into, so a visually backfilled card is still announced and focused in its original source position.
- Does grid-auto-flow: dense give you a masonry layout?No. Dense packing still places items into the grid's row and column tracks, so items remain aligned to shared row boundaries — it removes holes without staggering anything. A masonry effect needs items to sit at offsets independent of their neighbours' heights, which the standard row/column track model does not produce.
- Why can a dense grid look unstable as new items load in?Because each item is offered the earliest empty area that fits, a change anywhere in the sequence can re-decide many placements. Appending an item or letting one card grow can shuffle items that were already on screen. Sparse packing is stable in comparison: earlier placements never change when later items arrive, which is often worth more than a filled hole.
- If order does matter, what would you do instead of dense?Attack the arithmetic first — pick a track count that the spans divide evenly, or drop the span at the breakpoints where it strands cells. Failing that, reorder the source so the order you want to see is the real order, which keeps visual, reading and focus order in agreement. A visible hole is a cosmetic defect; a scrambled focus order is a functional one.
saying these in an interview costs you the question
- Claims dense also reorders the accessibility tree and tab order
- Calls dense a masonry layout
- Applies dense globally as a default for every grid
- Thinks dense reorders explicitly placed items too
- Says the visual/DOM mismatch does not matter if items look self-contained