auto-fill vs auto-fit: the visual difference
auto-fill and auto-fit look identical when items fill the container. The difference only appears when there are fewer items than tracks — and that difference matters.
The repeat() function refresher
Both auto-fill and auto-fit are used inside repeat() to create as many tracks as will fit in the available space. They replace a fixed column count with a responsive one.
/* Fixed: always 3 columns */
.grid-fixed {
grid-template-columns: repeat(3, 1fr);
}
/* Responsive: as many 250px-min columns as fit */
.grid-fill {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
.grid-fit {
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
Both create the same number of columns when items fill every track. The difference is what happens to empty tracks — tracks that exist but contain no items.
auto-fill: keeps empty tracks
auto-fill creates as many tracks as fit, even if some are empty. Empty tracks retain their size, which means items do not stretch to fill the remaining space. The extra tracks sit there, invisible but taking up room.
/* Container is 1200px wide, min column is 250px
→ 4 tracks are created (4 × 250px = 1000px, fits)
→ With only 2 items, tracks 3 and 4 are empty
→ Items stay at 250px–300px, empty space on the right */
.auto-fill-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
/* Result with 2 items in 1200px container:
[item1: ~287px] [item2: ~287px] [empty: ~287px] [empty: ~287px]
*/
Use auto-fill when you want items to maintain a consistent size regardless of how many there are. This is common in card grids where visual consistency matters more than filling the row.
auto-fit: collapses empty tracks
auto-fit also creates as many tracks as fit, but it collapses empty tracks to zero width. The remaining items stretch to fill all available space via the 1fr maximum.
/* Same container, same 2 items — different result */
.auto-fit-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
/* Result with 2 items in 1200px container:
[item1: ~593px] [item2: ~593px]
Empty tracks collapse → items stretch to fill the row
*/
Use auto-fit when you want items to expand and fill the available space. This works well for hero sections, feature grids, or any layout where items should feel expansive.
When they look the same
When the number of items fills all available tracks, auto-fill and auto-fit produce identical results. There are no empty tracks to collapse, so both behave the same way.
/* 4 items in a 1200px container with 250px minimum columns
→ 4 tracks created, 4 items fill them all
→ No empty tracks → auto-fill and auto-fit are identical */
/* Both produce: [item: ~287px] [item: ~287px] [item: ~287px] [item: ~287px] */
/* They also look the same when items wrap to multiple rows,
as long as each row is full of items */
auto-fill and auto-fit does not matter. Pick auto-fit as the safe default — it handles edge cases with fewer items more gracefully.The decision rule
The choice comes down to one question: when there are fewer items than columns, should items stretch to fill the row or stay at their minimum size?
- auto-fit — items stretch to fill the row. Good for: feature sections, pricing cards, hero layouts.
- auto-fill — items keep their minimum size, leaving empty space. Good for: product grids, thumbnail galleries, consistent card layouts.
/* Product grid — cards should be consistent, not stretch */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
gap: 1.5rem;
}
/* Feature section — items should fill the row */
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
gap: 2rem;
}
/* Dashboard widgets — consistent sizing */
.widgets {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
gap: 1rem;
}
Combining with explicit tracks
You can mix auto-fill or auto-fit with explicit track definitions, though this is less common. The explicit tracks are placed first, and the repeated tracks fill the remaining space.
/* Fixed sidebar + auto-fit content columns */
.layout {
display: grid;
grid-template-columns: 16rem repeat(auto-fit, minmax(12rem, 1fr));
gap: 1rem;
}
/* Fixed first column + flexible rest */
.table-like {
display: grid;
grid-template-columns: 4rem repeat(auto-fill, minmax(8rem, 1fr));
gap: 0.5rem;
}
Be careful with this pattern: auto-fill/auto-fit can only appear once in a grid-template-columns declaration, and it cannot be combined with another repeat().