Command Palette

Search for a command to run...

Hectal
PHASE 8Intermediate ~28 min· topic 2 of 6

Topic 8.2

repeat, minmax and Auto Tracks

In one line

repeat() writes many tracks at once, minmax() gives a track a smallest and largest size, auto-fill and auto-fit let the grid choose how many columns fit, and grid-auto-rows, grid-auto-columns and grid-auto-flow control the extra tracks the grid creates on its own.

Think of it like this

Seating guests at a party. You tell the host: "each chair needs at least 1 metre of table, and chairs share any extra space". The host fits as many chairs as the table allows, so a long table gets more chairs. When more guests arrive than you planned, the host sets up extra tables of a standard size. minmax() is the "at least 1 metre" rule, auto-fit is "as many chairs as fit", and the extra tables are the implicit grid.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

`repeat()`
A function that writes the same track (or pattern of tracks) many times.
`minmax()`
A function for one track's size: never smaller than the first value, never bigger than the second.
`auto-fill`
Inside repeat(): make as many tracks as fit, and keep empty ones.
`auto-fit`
Inside repeat(): make as many tracks as fit, then collapse the empty ones so items can stretch.
Explicit grid
The rows and columns you wrote in grid-template-rows and grid-template-columns.
Implicit grid
Extra rows or columns the browser adds when items don't fit the explicit grid.
`grid-auto-rows`
The size of rows the browser adds by itself. grid-auto-columns does the same for columns.
`grid-auto-flow`
Whether auto-placement fills rows or columns first, and whether it back-fills holes (dense).

Step by step

01Shorten a long template with repeat()

Twelve equal columns written by hand are hard to read. repeat(12, 1fr) says the same thing in one word.

style.csswhole filecss
.page {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 16px;
}

02Give each card a minimum width

repeat(3, minmax(200px, 1fr)) makes three columns that share the space but never go below 200px. On a narrow screen that's still three columns of 200px, so the grid overflows. A fixed count can't adapt.

style.csswhole filecss
.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  gap: 16px;
}

03Let the browser count the columns

Replace 3 with auto-fit. Now the browser asks: how many 200px columns (with gaps) fit? On a 900px screen, 4; on a 450px screen, 2. Then the 1fr maximum stretches them to fill the row.

Wrap the minimum in min() so a container narrower than 200px gets one full-width column instead of overflowing: minmax(min(200px, 100%), 1fr).

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

04Choose auto-fit or auto-fill

With only two cards in a wide row, auto-fill keeps the empty column slots, so the two cards stay small on the left. auto-fit collapses the empty slots, so the two cards stretch across the row.

Choose auto-fit or auto-filldiagram
Rendering diagram…

05Size the rows the grid adds

You defined columns but no rows, so every row is implicit. grid-auto-rows: minmax(120px, auto) makes each one at least 120px tall but lets it grow when a card has more text.

style.csswhole filecss
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-auto-rows: minmax(120px, auto);
  gap: 16px;
}

06Change the flow direction or pack holes

grid-auto-flow: column fills top to bottom and adds columns instead of rows. grid-auto-flow: row dense lets small items jump back into holes left by wide ones. Use dense only when the order of items doesn't matter (a photo wall), never for content people read in sequence.

style.csswhole filecss
.photos {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-flow: row dense;
}
.photos .wide {
  grid-column: span 2;
}

Try it yourself

  1. 1

    Predict the column count

    In the first example, change both minimums from 100px to 140px. Predict how many tracks fit in 460px with a 20px gap: (460 + 20) / (140 + 20) = 3. Then predict the .fill item width: (460 − 40) / 3 = 140. Run and check.

  2. 2

    Fill the auto-fill grid

    In the first example, add two more <div>s to both grids so each has four items. Predict the console: both grids now print the same tracks and widths, because no track is empty.

  3. 3

    Let the rows grow

    In the second example, change grid-auto-rows to minmax(40px, auto) and put a long sentence in item 5. Predict which row grows (row 2 only) and check the rows: line.

Code & diagrams

auto-fill vs auto-fit with two items New tab

Both grids fit 4 tracks: (460 + 20) / (100 + 20) = 4. `auto-fill` keeps the two empty tracks, so each item is 100px. `auto-fit` collapses them to 0px, so the two items share the whole row: (460 − 20) / 2 = 220px.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

.fill tracks: 100px 100px 100px 100px
.fill item width: 100
.fit tracks: 220px 220px 0px 0px
.fit item width: 220
The implicit grid and grid-auto-rows New tab

You defined one 60px row. Items 4 to 7 need two more rows, so the browser adds them at the `grid-auto-rows` size. The computed value lists implicit tracks too.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

columns: 96px 96px 96px
rows: 60px 40px 40px
grid-auto-flow: dense and column New tab

Item 3 needs two columns and can't fit in row 1's last cell, so it moves to row 2. Without `dense`, item 4 follows it (x=200, y=40) and the hole stays. With `dense`, item 4 goes back to the hole (y=0). In the column grid, items fill down two rows, then start a new 80px column.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

.sparse item 4 at x=200 y=40
.dense item 4 at x=200 y=0
.col item 3 at x=80 y=0
.col item 5 at x=160 y=0
How a grid growsdiagram
Rendering diagram…

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Use auto-fill with a plain fr

Write grid-template-columns: repeat(auto-fill, 1fr);.

terminal
$ the page shows
── what you'll see ──
The items stack in a single column. DevTools strikes the declaration through with an "Invalid property value" warning.

Break #2

A minimum that is too big for small screens

Use repeat(auto-fit, minmax(400px, 1fr)) and view the page on a 360px-wide phone.

terminal
$ the page shows
── what you'll see ──
The single column is 400px wide, so cards stick out of the screen and the page scrolls sideways.

Break #3

Dense packing breaks reading order

Add grid-auto-flow: dense to a list of numbered steps where some steps span two columns.

terminal
$ the page shows
── what you'll see ──
Step 5 appears before step 4 on screen, while Tab and screen readers still go 4 then 5.

Myth vs fact

Myth

auto-fill and auto-fit are the same thing.

Fact

They only differ when there are fewer items than tracks: auto-fill keeps the empty tracks, auto-fit collapses them so the items stretch.

Myth

You always need media queries to change the number of columns.

Fact

repeat(auto-fit, minmax(…, 1fr)) changes the column count by itself as the container gets wider or narrower. Media queries (Phase 9) are for bigger changes, like rearranging areas.

Myth

Items beyond the rows you defined are hidden or overflow.

Fact

The grid adds implicit rows (or columns) for them, sized by grid-auto-rows / grid-auto-columns.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The repetition count for auto-fill/auto-fit uses the track's max sizing function if it is definite, otherwise the min. So minmax(100px, 1fr) counts with 100px, but minmax(100px, 200px) counts with 200px. If the container has only a max-width, that is used; if its size is indefinite, you get one repetition.

  • ▸

    grid-template-columns and grid-template-rows are animatable between track lists of the same length in all current browsers, so grid-template-rows: 0fr → 1fr is a popular way to animate an accordion's height to its content without measuring it in JavaScript.

  • ▸

    grid-auto-rows and grid-auto-columns accept a list that repeats: grid-auto-rows: 100px 200px makes implicit rows alternate 100px, 200px. Implicit tracks before the explicit grid (created by negative placement) are sized from the end of the list backwards.

  • ▸

    Each repeat() in a template can only use auto-fill/auto-fit once, and that repeat may not contain fr or content-sized tracks (auto, min-content) on their own. Any other tracks beside it must also have fixed sizes: 200px repeat(auto-fill, 120px) is valid, 1fr repeat(auto-fill, 120px) is not.

Remember this

  1. 1

    **repeat(count, tracks)** saves typing: repeat(4, 1fr) is the same as 1fr 1fr 1fr 1fr. The tracks part can be a pattern: repeat(3, 100px 1fr) makes six tracks that alternate. You can mix it with other tracks: 200px repeat(3, 1fr) 200px.

  2. 2

    **minmax(min, max)** makes one track that is never smaller than min and never larger than max: minmax(150px, 1fr) is at least 150px and grows to share free space. minmax(100px, auto) is at least 100px and grows to fit its content. fr is only allowed as the max; and if min is bigger than max, the max is ignored. minmax(0, 1fr) is the fix for blowouts you saw in Topic 8.1.

  3. 3

    **auto-fill and auto-fit** replace the number in repeat(): repeat(auto-fill, minmax(150px, 1fr)) means "as many columns as fit, each at least 150px". The browser divides the container width (plus one gap) by the minimum track size plus a gap and rounds down. Then the 1fr maximum spreads the leftover across the columns. This one line gives a responsive gallery with no media queries: 4 columns on a wide screen, 2 on a phone.

  4. 4

    The two keywords differ only when there are fewer items than columns. auto-fill keeps the empty columns, so a few items stay at their small size and leave empty space on the right. auto-fit collapses the empty columns to 0 width (and the gaps around them), so the fr maximum lets the real items stretch across the whole row. With plenty of items, the two look identical. Note that auto-fill and auto-fit need a definite size inside: repeat(auto-fill, 1fr) is invalid, because the browser can't count how many 1fr tracks fit.

  5. 5

    The tracks you write in grid-template-* form the explicit grid. When items need more room (more items than cells, or an item placed on line 7 of a 3-column grid), the browser adds tracks to the implicit grid. Their size comes from **grid-auto-rows and grid-auto-columns**, which default to auto (fit the content). grid-auto-rows: minmax(120px, auto) is a favourite: every new row is at least 120px tall but can grow for long content.

  6. 6

    **grid-auto-flow** chooses how auto-placement fills the grid. row (the default) fills each row and adds rows. column fills each column top to bottom and adds columns, sized by grid-auto-columns. Adding **dense** (grid-auto-flow: row dense) lets later small items go back and fill holes left by earlier big items. That packs the grid tightly, but the visual order no longer matches the HTML order, which confuses keyboard and screen-reader users who move through the page in HTML order.

Explain it without notes

01

What does minmax(200px, 1fr) mean for one track?

02

Explain the difference between auto-fill and auto-fit, and when you can see it.

03

What is the implicit grid, and which properties size it?

04

What does grid-auto-flow: dense do, and what is its accessibility risk?

Practice

01

Write a gallery grid where every card is at least 180px wide, cards share any extra width, and there's a 16px gap, with no media queries.

02

A grid has grid-template-columns: repeat(4, 1fr) and 10 items. You want every row to be at least 150px tall but taller when needed. Write the CSS.

03

Write a grid that lays out its items in columns of three, top to bottom, adding new 120px-wide columns to the right as needed.

Trade-offs

  • ↔

    auto-fit galleries adapt without media queries, but you no longer pick the exact column count at each width; when a design needs "exactly 2 columns on tablets", use a fixed repeat() inside media or container queries.

  • ↔

    dense packing removes holes but sacrifices order; keep it for decorative collections.

Done when you can

  • I can write long track lists with repeat() and give tracks limits with minmax().

  • I can build a responsive gallery with repeat(auto-fit, minmax(min(…, 100%), 1fr)).

  • I can predict when auto-fill and auto-fit look different.

  • I can size implicit rows and columns with grid-auto-rows and grid-auto-columns.

  • I can switch the flow to columns and explain the risk of dense.