CSS Grid Auto-Placement Algorithm

What You Learn From This Page

  • How Grid places items that have no complete coordinates.
  • How row-first and column-first flows advance through cells.
  • How definite, partially positioned, and fully automatic items interact.
  • Why spans create holes and implicit tracks.
  • How sparse and dense packing differ.
  • Why dense layouts can conflict with reading and keyboard order.
  • How auto-fit and auto-fill differ from item auto-placement.
  • How to debug cards, galleries, dashboards, and dynamic data grids.

Introduction

The CSS Grid auto-placement algorithm determines where Grid items go when the stylesheet does not provide a complete row and column coordinate for every item. Authors define tracks and special exceptions; the browser finds available cells for the remaining direct children. This allows dynamic collections to grow without a selector for each position.

Auto-placement is not random. It follows source order, the configured flow direction, item spans, already occupied areas, and a placement cursor. It may generate implicit rows or columns when the explicit grid lacks enough space. Understanding that model explains why a large card moves to a new row, why a hole remains behind, or why an item unexpectedly creates horizontal overflow.

The most maintainable strategy is usually to let regular repeated items auto-place and explicitly place only meaningful exceptions. A featured card can span two tracks while every standard card follows the normal algorithm. This keeps CSS independent from exact result counts and lets applications respond to filtering, sorting, permissions, and asynchronous data.

What Is Auto-Placement?

An item is fully auto-positioned when neither its row nor column is explicitly resolved. Grid examines the available structure and selects the next suitable unoccupied position.

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
}

Five direct children fill the first three columns and then continue into the second row. No item-specific placement is needed.

The Default Flow Is Row-First

The initial value is grid-auto-flow: row. The algorithm fills positions across the current row, then advances to the next row. In a three-column grid, items A through G appear as A B C, then D E F, then G.

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

Writing direction influences where row traversal begins visually, but the source sequence remains the basis for normal placement.

Column-First Flow

grid-auto-flow: column changes the primary placement direction. Items fill positions down columns before advancing to another column. A definite row structure is often needed to produce the intended pattern.

.schedule {
  display: grid;
  grid-template-rows: repeat(3, auto);
  grid-auto-flow: column;
}

Column flow is less common for ordinary web content because source reading frequently proceeds row by row. It is useful for selected vertically oriented lists, schedules, and matrix interfaces where column progression is meaningful.

Explicit and Implicit Tracks

Template properties create the explicit grid. When auto-placement needs additional space, the browser creates implicit tracks. A grid with three explicit columns and no row template can generate as many implicit rows as its item count requires.

Implicit tracks are normal and support dynamic data. They become a problem when they are created on the wrong axis by accidental placement or receive unsuitable default sizing.

Control Auto-Created Rows

grid-auto-rows defines the size of implicit rows. A minimum with an automatic maximum supports consistent cards without clipping long content.

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: minmax(10rem, auto);
}

Every generated row is at least 10rem and can grow. A fixed row height is appropriate only when overflow is intentionally managed inside the item.

Control Auto-Created Columns

grid-auto-columns sizes implicit columns. It is particularly relevant to column flow or items explicitly placed beyond the declared column template.

.timeline {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 12rem;
}

Column-first layouts can grow horizontally, so provide a deliberate overflow or pagination strategy when the number of generated columns is unbounded.

Source Order Is the Starting Sequence

Under normal sparse placement, automatic items are considered in order-modified document order, which usually matches the DOM when order is not used. Keeping this sequence meaningful makes the visual flow, reading order, and keyboard order easier to understand.

CSS should not rely on auto-placement to repair illogical markup. Write the content in the intended task sequence and use Grid to provide two-dimensional presentation.

Fully Positioned Items

An item with definite row and column placement already has a resolved area. Auto-placement accounts for that occupied region when it places remaining items.

.summary {
  grid-column: 2 / 4;
  grid-row: 1 / 3;
}

Explicit areas can reserve space before fully automatic siblings are resolved. Their position and spans may therefore reshape the rest of the sequence.

Items Fixed on One Axis

An item can have a definite column but an automatic row, or a definite row but an automatic column. The algorithm respects the known axis and searches for a valid position on the unresolved axis.

.priority {
  grid-column: 2;
}

This item remains in column 2 but moves to the next row where its required area is free. Partially positioned items are a useful middle ground, though too many can make the final layout difficult to predict.

A Practical Placement Sequence

The formal algorithm contains detailed phases, but a useful engineering model is to identify items with definite positions, account for items definite on one axis, expand the implicit grid when necessary, and then place fully automatic items by advancing a cursor through candidate cells.

This simplified sequence explains most debugging cases without replacing the specification. The important point is that explicitly occupied areas and span requirements influence the search space before ordinary items settle into their cells.

The Auto-Placement Cursor

The browser maintains a conceptual cursor indicating where its next search begins. In row flow it advances across columns and then down rows. Sparse placement normally keeps moving forward after placing each item rather than restarting at the first cell.

Authors do not set the cursor directly. They influence it by changing flow direction, explicit placement, item spans, the number of tracks, and dense packing behavior.

Auto-Placement with Spans

An automatic item can request a span without naming an exact start. Grid searches for the next available region wide and tall enough for that rectangle.

.card--featured {
  grid-column: span 2;
}

.card--large {
  grid-column: span 2;
  grid-row: span 2;
}

A two-by-two item requires four free cells arranged as one rectangle. A nearby collection of individual holes cannot satisfy the request.

Why Spans Can Leave Holes

If the current row has one cell left and the next item spans two columns, that item cannot fit. Sparse placement moves it to a later row, leaving the single cell empty. The cursor then continues forward, so a later one-column item does not normally return to fill that earlier hole.

This behavior protects predictable visual progression. The empty space is not necessarily an error; it is a result of preserving source-order placement while respecting spans.

Sparse Packing

The default row or column flow is sparse. The algorithm does not aggressively search backward after every item. Earlier gaps may remain when mixed spans do not fit the current cursor position.

Sparse packing is generally best for articles, products, results, forms, navigation, and other meaningful sequences. Users see content in approximately the same progression in which it appears in the DOM.

Dense Packing

Adding dense asks Grid to backfill earlier holes when a later item fits. It can be combined with row or column flow.

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

Dense packing changes placement search behavior, not track sizing or item dimensions. A two-column item still needs two adjacent free columns.

Dense Packing Can Change Visual Order

A later small item may fill a hole before an earlier large item appears visually. The DOM sequence does not change, and screen readers and keyboard focus generally continue to follow source order. The result can be a visible sequence such as A, C, B while interaction follows A, B, C.

Use dense packing only when independent items can be understood without meaningful visual sequence, such as selected image galleries or decorative tiles. Avoid it for forms, instructions, navigation, chronological feeds, and keyboard-heavy cards.

row dense and column dense

row dense uses row-first traversal with backfilling. column dense uses column-first traversal with backfilling. The shorthand value dense retains the initial row direction while enabling dense behavior.

Choose the primary direction according to how users interpret the content, then decide separately whether backfilling is acceptable. Direction and density solve different problems.

Mix Explicit and Automatic Placement

A strong production pattern defines regular tracks, lets most children auto-place, and gives only selected items a span or area.

.articles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
}

.article--featured {
  grid-column: span 2;
}

This keeps the list data-driven. Adding or removing ordinary articles does not require CSS changes, while featured content retains a deliberate visual emphasis.

Full-Width Items in Automatic Collections

A banner, notice, or section break can span the complete explicit grid while surrounding cards remain automatic.

.collection-banner {
  grid-column: 1 / -1;
}

The banner reserves a full row according to its placement point in source order. Later items continue from the next available area. This is useful for inline promotions and result-group headings when their DOM position matches their meaning.

Auto-Placement with Named Areas

Items assigned to named areas are explicitly positioned in those regions. Unassigned direct children may still auto-place into available Grid cells, but mixing structural areas and repeated data in one large grid can be hard to reason about.

A clearer architecture uses named areas for the outer shell and an inner Grid inside the main area for repeated cards. Each algorithm then owns one understandable scope.

Auto-Placement and Responsive Track Counts

auto-fit or auto-fill determines how many repeated tracks fit. The auto-placement algorithm determines which item occupies each available area. They cooperate but are not the same feature.

.products {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  grid-auto-rows: minmax(10rem, auto);
  gap: 1rem;
}

As the track count changes, source-ordered items automatically flow into the new rows. No item-specific media-query placement is needed.

Dynamic Data Is a Natural Fit

API results, search cards, user records, and media collections often have unknown counts. Auto-placement handles three items, ten items, or one hundred items with the same container rules. Filtering and sorting update the DOM, and Grid recalculates positions.

This does not remove the need for pagination, virtualization, or performance decisions for very large lists. It simply decouples visual cell assignment from item count.

Hidden Items and Reflow

An item with display: none does not generate a Grid item box, so it occupies no area and later items reflow. An item with visibility: hidden remains in the layout and keeps its assigned or automatic position while becoming visually hidden.

Choose based on interaction and semantics, not merely the desired gap. A visually hidden interactive item also needs correct focus and accessibility handling.

Explicit Placement Can Generate Implicit Tracks

If a three-column grid places an item at column line 8, Grid creates implicit columns to satisfy that coordinate. This can produce a wide empty region and horizontal overflow.

Use browser overlays to distinguish legitimate auto-created rows from accidental implicit columns. If horizontal expansion is intentional, define grid-auto-columns and a suitable scrolling or navigation model.

Grid Auto-Placement Versus Flex Wrapping

Flexbox places items sequentially along a main axis and creates another flex line when wrapping is enabled. Grid first establishes a two-dimensional track system and searches it for available rectangular areas. Similar rows of cards can result, but the sizing and placement models differ.

Use Grid when shared columns, row spans, and two-dimensional holes matter. Use Flexbox when the primary relationship is one row or column and each wrapped line can size independently.

A Card Grid

Regular cards need no individual coordinates. A responsive track definition and gap can carry the complete placement logic.

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1rem;
}

This is more maintainable than assigning columns to card1, card2, and card3. It also behaves correctly when a card is conditionally absent.

A Bento Grid

Bento-style layouts combine regular cells with larger items. Dense placement can reduce gaps, but only when visual ordering is not meaningful.

.bento {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: minmax(10rem, auto);
  grid-auto-flow: dense;
  gap: 1rem;
}

.bento-large {
  grid-column: span 2;
  grid-row: span 2;
}

Provide simpler spans and fewer columns at narrow widths. Test varied content heights because visual mosaics can become difficult to scan when every tile has different density.

A Photo Gallery

A gallery can use landscape and portrait metadata to set spans. Dense packing may be appropriate when images are independent and their source order is not chronological or instructional.

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  grid-auto-flow: dense;
  gap: 0.75rem;
}

.gallery-landscape {
  grid-column: span 2;
}

Preserve meaningful captions and alternative text. Dense visual packing does not reduce the need for coherent source metadata.

A Dashboard Widget Grid

Dashboard widgets often use a fixed logical track count at wide widths and selected spans for analytics panels.

.dashboard-widgets {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: minmax(8rem, auto);
  gap: 1rem;
}

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

Dashboards are interactive and often ordered by priority, so sparse flow is generally safer than dense packing. Let intentional empty space remain when backfilling would scramble the scan and focus sequence.

Use order with Caution

The order property affects order-modified document order and can therefore influence placement sequence. It does not rewrite DOM reading or default focus order. Combining custom order, spans, and dense packing creates a layout that is difficult to predict and potentially inaccessible.

Prefer meaningful DOM order. Use explicit structural placement for a small number of exceptions rather than treating order as a data-sorting mechanism.

A Closer Look at Placement Phases

The browser does not treat every Grid item identically. Items whose row and column positions are both definite can be committed to their areas without a search. Items that have a definite position on one axis still need the algorithm to resolve the other. Items with no definite axis depend entirely on the auto-placement cursor. Spans and explicit positions can also require the implicit grid to expand before later items are considered.

This phased behavior matters when debugging because the first element in the DOM is not always the first one that determines occupied space. A later element with complete coordinates can reserve an area that an earlier automatic item might otherwise have used. The automatic item is then placed around that reservation.

Think of explicit placement as defining structural constraints and automatic placement as filling the remaining structure. This is more accurate than imagining that every item is simply processed from beginning to end with no preparation.

Worked Cursor Example

Consider a three-column grid with five source-ordered items. Item A spans two columns, B spans two columns, and C, D, and E occupy one column each. The cursor begins at the first cell and places A across columns one and two. B cannot fit in the one remaining cell, so sparse row flow advances to the next row and places B across columns one and two there.

The first row now contains a hole in column three. Because sparse placement continued to the second row, C is placed in the remaining third column beside B rather than returning to the hole above. D and E continue into the next row. The empty first-row cell is therefore an expected result of cursor progression and span constraints.

With dense packing, the algorithm may test that earlier hole for C and place C there before continuing with D and E. The visual result is more compact, but C now appears visually ahead of B even though B precedes it in source. This small example captures the central sparse-versus-dense tradeoff.

Definite Placement Can Overlap

Two explicitly positioned items can target the same Grid area. Grid does not automatically move one away to prevent overlap because both declarations are definite. They paint according to document and stacking rules. This may be intentional for overlays, but it can also indicate duplicate coordinates.

Auto-placed items avoid occupied cells according to the algorithm, while definitively overlapping items express the author's choice. When content disappears beneath another item, inspect whether both axes are explicit before blaming auto-placement. Changing grid-auto-flow cannot resolve a collision created by two complete coordinate declarations.

Responsive Span Resets

A span designed for four desktop columns may be impossible or undesirable in a one-column mobile template. Although Grid can create implicit tracks to satisfy some placement requests, that expansion may cause horizontal overflow rather than an adaptive result. Reset exception rules when the explicit track system changes.

.card--featured {
  grid-column: auto;
  grid-row: auto;
}

@media (min-width: 50rem) {
  .card--featured {
    grid-column: span 2;
  }
}

A mobile-first rule lets all cards auto-place normally and introduces the wider span only when at least two useful columns exist. When using container queries, base that decision on the component's available width rather than the top-level viewport.

Placement in Right-to-Left and Vertical Writing Modes

Row and column flow follow Grid's logical axes. In right-to-left content, the inline-start edge changes, so the first visual column appears on the right. Source order and row-first progression remain logical rather than permanently left-to-right.

Test the actual direction state when visual order matters. Physical margins, directional icons, and text alignment can contradict a Grid that otherwise adapts correctly. Column-first layouts in vertical writing modes further demonstrate why the flow should be understood as row and column progression rather than memorized physical directions.

Auto-Placement and Generated Content

Only generated boxes that participate as Grid items affect placement. Direct text runs can create anonymous Grid items, while pseudo-elements on the container can also participate in ways that surprise an author expecting only element children. Meaningful content should usually be wrapped in semantic elements so its placement and styling are explicit.

Extra wrappers have the opposite effect: the wrapper is the direct Grid item, and its children do not independently auto-place in the outer grid. If each child needs a cell, establish a nested grid or reconsider a purely presentational wrapper without removing useful semantic grouping.

State Changes and Layout Stability

Removing an item with display: none, changing a feature flag, or filtering results causes the complete automatic layout to be recalculated. Every later card may move. That is usually correct for a visual collection, but it can be disorienting when users are tracking a particular position or when live updates occur frequently.

Preserve stable identifiers and focus management when DOM updates move items. Avoid leaving focus inside content that is removed. If visual position carries business meaning, explicit semantic grouping, sorting labels, or a less fluid layout may be better than relying on cell location.

Loading placeholders should use span rules compatible with final content. Otherwise, the grid can shift dramatically when a one-cell skeleton becomes a two-column featured card. Test the transition from loading through success, empty, and error states.

Auto-Placement and Component Boundaries

A reusable component should own its track creation, item spans, and flow behavior. Parent pages should not reach deeply into its children to assign row and column coordinates, because those rules couple the component to one embedding context. Let the parent place the component as one Grid item and let the component auto-place its own repeated children.

Nested grids also limit the impact of implicit tracks. An inner product grid can grow through rows without changing the outer page shell's column architecture. Clear ownership makes developer-tool overlays easier to interpret because each placement algorithm has a smaller scope.

Performance and Large Collections

Grid auto-placement is implemented by the browser and is appropriate for ordinary application collections. Dense packing performs more searching than sparse placement because it examines earlier holes, so it should not be enabled without a visual requirement. In very large feeds, DOM size, image loading, rendering, and application updates usually matter more than the basic sparse algorithm.

Pagination, windowing, and content visibility can reduce rendering work for thousands of records, but these techniques introduce their own accessibility and measurement concerns. Do not manually calculate cell positions in JavaScript merely to replace a layout capability the browser already provides.

Choosing Sparse or Dense by Content Meaning

The decision should come from semantics, not the attractiveness of a compact screenshot. Sparse flow is the default for products sorted by relevance, articles sorted by date, settings, instructional steps, and any interactive sequence. Empty cells are acceptable when they preserve understandable progression.

Dense flow is more defensible for nonsequential image mosaics, decorative portfolios, and independent visual tiles. Even then, captions and keyboard-focusable controls may reintroduce meaningful order. Run the interface without CSS or follow focus through it to verify that the source sequence still makes sense.

Common Mistakes and Better Choices

MistakeBetter Choice
Manually placing every cardLet regular items auto-place
Using dense for ordered contentKeep sparse flow when sequence matters
Ignoring implicit row sizingDefine grid-auto-rows for consistent dynamic rows
Placing an item far outside the templateCorrect the line or deliberately size implicit columns
Expecting dense to resize itemsAdjust track sizes and spans separately
Confusing auto-fit with placementSeparate track creation from item assignment
Treating Grid like Flex wrappingReason about two-dimensional available areas
Using order to repair source sequenceCorrect the DOM order

Debugging Auto-Placement

Enable the browser's Grid overlay and identify explicit tracks, implicit tracks, occupied areas, and empty cells. Check whether flow is row or column and whether dense packing is active. Then inspect each surprising item's row, column, and span values.

Look earlier in source order for a large or explicitly positioned item that reserved the expected cells. If the grid grows on the wrong axis, inspect any coordinates outside the explicit lines. If gaps remain, determine whether sparse progression and span requirements explain them before adding manual placement.

1. Confirm row-first or column-first flow
2. Check whether dense packing is enabled
3. Display explicit and implicit tracks
4. Inspect definite and partially definite items
5. Check each item's row and column spans
6. Identify occupied cells before the item
7. Verify order and source sequence
8. Test the same grid with realistic item counts

Production Testing

Test no items, one item, a complete row, a partially filled row, and enough items to generate several implicit rows. Include every featured span at the beginning, middle, and end of the sequence. A layout that works for one curated order may develop holes or overflow with real data.

Test filtering, sorting, permission-based removal, loading placeholders, and live insertion. Each DOM change can produce a new placement result. Confirm that animations or transitions do not imply an incorrect relationship between old and new positions.

Test keyboard navigation, screen-reader sequence, zoom, right-to-left direction, translated labels, and long content. A visually compact grid is not successful if focus jumps unpredictably or a wide descendant creates implicit overflow.

Sparse and Dense Comparison

ValueDirectionBackfills Holes
rowRow-firstNo
columnColumn-firstNo
row denseRow-firstYes
column denseColumn-firstYes
denseInitial row-first directionYes

Common Interview Questions

What is CSS Grid auto-placement? It is the browser algorithm that positions Grid items whose row and column placement is not fully specified.

What is the default grid-auto-flow value? The default is row.

What does column flow do? It fills positions down columns before advancing to another column.

What does dense do? It allows later items to backfill earlier holes when their spans fit.

Why can dense packing be risky? The visual order may differ from DOM, reading, and keyboard focus order.

What are implicit tracks? They are rows or columns created automatically when placement needs space beyond the explicit grid.

How are implicit rows and columns sized? Use grid-auto-rows and grid-auto-columns.

Should every item be manually placed? No. Regular repeated items should normally auto-place; manual placement is best for structural or featured exceptions.

Practical Review Checklist

  • Let regular repeated items auto-place.
  • Reserve explicit placement for meaningful exceptions.
  • Use row flow for ordinary source-ordered collections.
  • Use column flow only when vertical progression is meaningful.
  • Keep sparse packing when sequence matters.
  • Use dense only for independent content that tolerates visual reordering.
  • Define implicit row or column sizes when their dimensions matter.
  • Use spans instead of coordinates for adaptable featured items.
  • Watch for accidental implicit columns and horizontal overflow.
  • Keep DOM, reading, and focus order coherent.
  • Test dynamic item counts and application states.
  • Use Grid overlays to inspect the actual placement result.

Key Takeaway

The auto-placement algorithm lets Grid perform repetitive cell assignment. Define a useful track system, keep content in logical source order, allow normal items to flow automatically, and add explicit spans or areas only for real structural exceptions. Grid creates implicit tracks when additional space is required.

The default sparse row flow offers the most predictable relationship between source and visual order. Dense packing can fill holes in bento and gallery layouts, but it may move later items into earlier visual positions. Choose that tradeoff deliberately, test interaction order, and use developer tools to inspect every implicit track and occupied area.