Lesson 29 of 30
You already know grid-template-columns and grid-template-areas. This lesson is about composing that knowledge with subgrid and container queries into patterns that hold up in a real, unpredictable layout.
13 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
A card grid uses `grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr))`. It currently holds only 2 cards in a row that could fit 4. What happens to the 2 unused tracks?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
This lesson assumes you already know basic CSS Grid — grid-template-columns, grid-template-areas, placing items with grid-column/grid-row. What's worth covering at a working level isn't more grid syntax in isolation, but how grid composes with two other ideas already covered in this track: subgrid (letting a nested grid share its parent's tracks instead of defining its own) and container queries (letting a component respond to the size of its own containing box rather than the viewport). Real layouts rarely use one grid feature at a time — they combine a responsive track pattern, semantic naming, and nested alignment into something that holds up as content changes.
Three patterns worth having ready:
repeat(auto-fit, minmax(...)) for a card grid that reflows its column count with zero media queries.grid-template-areas-style layouts that read like a floor plan instead of a column-counting exercise..card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1.5rem;
}
repeat(auto-fit, minmax(16rem, 1fr)) tells the browser: fit as many 16rem-minimum columns as will comfortably fit, and let each one grow to fill any leftover space. Resize the container and the column count changes on its own — three columns on a wide screen, one on a narrow one — with no breakpoint written anywhere. This is the pattern that replaced a lot of hand-written media-query grids.
auto-fit and auto-fill are commonly confused and behave differently the moment you have fewer items than would fill a row. Both compute the same number of tracks that could fit; the difference is what happens to the ones that don't get an item:
/* auto-fit: empty tracks collapse to zero width — the 2 cards stretch to fill the row */
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
/* auto-fill: empty tracks stay reserved at their minimum width — the 2 cards stay
their natural size and leave visible empty space where the missing cards would go */
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
With 2 cards in a row that could fit 4, auto-fit collapses the 2 unused tracks and lets the existing cards' 1fr stretch to absorb the freed space. auto-fill leaves those 2 tracks present-but-empty, so the cards stay at their minimum size with visible gaps beside them. Neither is "correct" — auto-fit is almost always what a card grid wants; auto-fill is right when you deliberately want consistent track sizing regardless of item count (a calendar grid, for instance).
Named grid lines make a grid-template-areas-equivalent layout self-documenting when the shape is more irregular than areas comfortably express:
.page {
display: grid;
grid-template-columns: [sidebar-start] 16rem [sidebar-end content-start] 1fr [content-end];
}
.sidebar {
grid-column: sidebar-start / sidebar-end;
}
.sidebar's placement reads as what it means, not as "column 1" — a later change to the number of tracks doesn't silently break a hardcoded grid-column: 1, because the line names travel with the layout's intent.
Subgrid is where this composes with nested components: a card inside .card-grid that needs its own header, body, and footer to align vertically with every other card's header, body, and footer — not just be internally consistent within itself — declares its rows as subgrid instead of defining new ones:
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3;
}
Without subgrid, each .card would need its own row sizing guessed independently, and cards with different amounts of content would drift out of alignment with their neighbors. With grid-template-rows: subgrid, the card's three rows are three of the parent grid's tracks — sized once, by the parent, and shared.
auto-fit versus auto-fill is invisible until item count is less than what fills a row. With a full grid, the two look identical — the difference only becomes visible with a partial last row, which is exactly the scenario that's easy to skip in testing and easy to notice in a real interview whiteboard question.minmax(16rem, 1fr) needs both bounds to make sense. A bare 1fr with no minimum lets columns shrink arbitrarily; a bare fixed width with no 1fr maximum doesn't reflow at all. The pattern's responsiveness comes specifically from pairing a hard minimum with a flexible maximum.grid-template-rows: subgrid shares row tracks; it says nothing about columns unless grid-template-columns: subgrid is also declared. Forgetting this is a common reason "subgrid isn't working" turns out to mean "it's only working on one axis."grid-template-areas solve the same self-documentation problem two different ways — areas read better for simple rectangular regions, named lines read better for layouts where the same line needs a name from multiple contexts (a line that's both a sidebar's end and content's start, as in the example above).auto-fit reflows based on the grid's available space; a container query inside one card can still change that card's own internal layout based on the card's own size, independent of how many siblings currently share the row. They're solving different granularities of the same responsive-layout problem."Build a responsive card grid that doesn't use a single media query" is a common practical prompt, and reaching for repeat(auto-fit, minmax(...)) — plus being able to explain the auto-fit/auto-fill distinction when asked what happens with 2 cards instead of 8 — is the difference between having memorized the pattern and actually understanding what it does.