CSS Grid repeat(): How to Create Repeating Tracks
Use CSS Grid repeat() for fixed or responsive tracks. Learn when to choose auto-fill or auto-fit, how minmax() works, and how to avoid common layout problems.
CSS Grid’s repeat() function writes a track pattern once and repeats it. Use a number for a fixed count, such as repeat(3, 1fr), or use auto-fill or auto-fit with a suitable minmax() when the number of columns should respond to the container’s width.
Basic syntax and a fixed number of tracks
The general form is repeat(count, repeated-value-list). In Grid, use it in track-list properties such as grid-template-columns and grid-template-rows. The repeated pattern can contain one or more track sizes and optional line names.
<div class="grid">
<article>One</article>
<article>Two</article>
<article>Three</article>
</div>
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
This creates three equal fractional columns. 1fr shares available space among the tracks after the grid accounts for gaps and other sizing constraints. If the layout must remain two columns at every width, for example, choose the fixed count deliberately and define how the component behaves at narrow widths with media queries or a different layout.
Responsive columns with auto-fill or auto-fit
When the column count should depend on available width, use an auto-repeat keyword with a pattern that has a definite minimum size and a flexible maximum:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
gap: 1rem;
}
The browser calculates how many tracks with the 230px minimum fit in the available space. Each track can then grow up to the flexible 1fr maximum. The 230px value is an example, not a universal recommendation; set the minimum according to the content and the component’s container.
Choosing between auto-fill and auto-fit
| Keyword | What happens to empty repeated tracks? | Use it when |
|---|---|---|
auto-fill |
The calculated track slots remain, even if there are no items in some of them. | You want the layout to preserve those slots and the space they occupy. |
auto-fit |
After placement, empty repeated tracks collapse, along with their adjacent gutters. | You want occupied tracks to expand into the space that empty tracks would have used. |
Both keywords calculate how many repetitions fit. The difference is visible when there are fewer grid items than available tracks. With a fixed number of items, auto-fit can make occupied cards wider; auto-fill preserves the unused slots. Neither is universally preferable: choose based on the desired empty-space behavior.
/* Preserve available slots when some are empty */
.gallery--slots {
grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
}
/* Let occupied tracks expand into unused space */
.gallery--stretch {
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}
Use minmax() to set a responsive track range
minmax(minimum, maximum) gives a track a lower and upper sizing bound. In the common pattern minmax(230px, 1fr), the fixed minimum gives auto-repeat a size to use when calculating how many tracks fit, while 1fr lets tracks share extra space.
.product-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
gap: 1.25rem;
}
Choose the minimum based on the narrowest width at which the content remains usable. Long unbreakable text, intrinsic image dimensions, padding, and borders can make a card’s effective minimum larger than expected. If a minimum is too large for the container, fewer columns fit and the layout may overflow at very narrow widths. Reduce the minimum, allow content to wrap or shrink, or add a breakpoint suited to the component.
Repeat patterns, rows, and line names
The repeated list can contain multiple tracks, so one repeat can describe a recurring pattern rather than just one track. Fixed-count repeats also support named grid lines:
.report {
display: grid;
grid-template-columns: repeat(2, [column-start] minmax(10rem, 1fr) [column-end]);
grid-template-rows: repeat(3, minmax(4rem, auto));
gap: 1rem;
}
Here the column pattern repeats twice, and the row sizing pattern repeats three times. Use line names when they make placement rules clearer; names repeated in a pattern can identify corresponding lines in each repetition.
For a fixed pattern of different track sizes, repeat the group instead of spelling it out repeatedly:
.alternating {
display: grid;
grid-template-columns: repeat(3, minmax(8rem, 1fr) 2fr);
}
This defines six columns by repeating a two-track pattern three times.
Syntax rules and constraints
- The repeated fragment goes in a Grid track-list property such as
grid-template-columnsorgrid-template-rows. - A fixed repeat count must be a positive integer.
- A track list can contain at most one auto-repeat function. Other repeated groups in the list must follow the fixed-repeat constraints.
- Auto-repeat patterns have track-size restrictions. A pattern such as
minmax(230px, 1fr)has a fixed minimum and flexible maximum, which is a useful responsive form; a pattern made only of fully intrinsic or flexible sizes is not suitable for auto-repeat. - Do not nest one
repeat()inside another.
See the MDN repeat() reference for the formal syntax and restrictions, and its Grid layout guide for track sizing concepts.
Common problems and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Only one column appears | The container is too narrow for another copy of the minimum track size, including gaps. | Reduce the minmax() minimum or give the component more width. Check the actual container width rather than the viewport width. |
| The grid overflows on small screens | The minimum track size, padding, gap, or unbreakable content is wider than the available space. | Lower the track minimum, let text wrap, constrain wide media, or add a narrow-screen rule. |
| Cards do not expand to fill the row | auto-fill retains empty tracks, or the maximum track sizing prevents growth. |
Try auto-fit if empty tracks should collapse, and check that the maximum is flexible, such as 1fr. |
| Columns are wider than expected | auto-fit collapsed empty tracks, allowing occupied tracks to expand. |
Use auto-fill to preserve the empty slots, or set a fixed maximum track size if cards should stop growing. |
| The CSS declaration is invalid | The auto-repeat pattern violates sizing restrictions, the track list includes multiple auto-repeat functions, or repeat() is nested. |
Use one auto-repeat with a valid track pattern, and express any other repetitions as fixed repeats where allowed. |
| A card is wider than its track | Its content has a large intrinsic minimum, such as a long unbroken string or image. | Allow wrapping, constrain the media, and consider min-width: 0 on the grid item when its contents should be allowed to shrink. |
Performance, reliability, and cost
repeat() is CSS syntax for describing tracks; it does not require a library, API, or paid service. For ordinary component layouts, choose a track minimum and pattern that match the content, then verify the result at the container widths where the component is used. A CSS grid adapts locally as its available width changes, so it is a good fit for card collections and galleries whose item count can vary.
If you are documenting, reviewing, or debugging the rendered result across pages, a screenshot can make layout changes easier to inspect. Avoid capturing every tiny resize during development; capture representative viewport sizes and states, and wait for dynamic content to settle before comparing images.
Or skip the browser setup
If you need screenshots of a page to document or inspect your Grid layout, ScreenshotNeo is a website screenshot API and MCP server for developers. Its one-call API can return a PNG, JPEG, WebP, or PDF; see the API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Cookie banners are accepted and removed before capture, along with known newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. An MCP server gives AI agents tools to take screenshots, inspect page information, and capture PDFs. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, no card required.
FAQ
Can repeat() be used with grid-template-rows?
Yes. It repeats row track sizes in grid-template-rows, just as it can repeat column track sizes in grid-template-columns.
Does auto-fit always make a better responsive grid?
No. It collapses empty repeated tracks and their gutters after placement. Use it when occupied tracks should expand; use auto-fill when empty slots should remain part of the layout.
What should I choose for the minimum in minmax()?
Choose the smallest track width at which the content still works, accounting for padding, gaps, and intrinsic content. The right value depends on the component.
Can I mix repeat() with explicit tracks?
Yes, subject to the auto-repeat and track-list restrictions. A list may include ordinary explicit tracks and fixed-repeat groups alongside one auto-repeat.


