Grid
Define flexible tracks
Build fixed and flexible tracks with fr, repeat, minmax, auto-fit, and auto-fill for layouts that adapt to available space.
The power of Grid is in how you size the tracks. You can mix fixed and flexible values in one line, and you can let the browser decide how many columns fit.
A sidebar that is at least 12rem but can grow, next to a main area three times as flexible:
.layout {
display: grid;
grid-template-columns: minmax(12rem, 1fr) 3fr;
}
minmax() takes a minimum and a maximum. The first column never drops below 12rem. Above that, the two columns share leftover space one to three.
repeat()
Typing 1fr 1fr 1fr gets old. repeat() does it for you:
grid-template-columns: repeat(3, 1fr);
Same three equal columns, easier to change to four.
Let the browser count the columns
This is the line I use on almost every card grid:
grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
Let’s read it from the inside out. Each column is at least 16rem and at most one fraction of the space. auto-fit tells the browser to create as many of those columns as fit in the container. On a wide screen you get four, on a phone you get one. No media query.
auto-fill does the same counting, but it keeps the empty tracks when there are fewer items than columns. auto-fit collapses them, so the existing items stretch to fill the row. For a card grid you almost always want auto-fit.
The inner min(16rem, 100%) is a small safeguard. Without it, a container narrower than 16rem would still get a 16rem column and overflow. With it, the minimum becomes “16rem or the full width, whichever is smaller”.
The hidden minimum in 1fr
A plain 1fr track is really minmax(auto, 1fr). That auto minimum honors the content’s min-content size. So a long unbreakable URL in one card makes its column wider than the others, and the “equal” columns are not equal anymore.
When a track must be able to shrink below its content, say so:
grid-template-columns: repeat(3, minmax(0, 1fr));
Now the columns stay equal. The long content still needs handling on the child, with overflow-wrap: anywhere or overflow-x: auto, or it will spill out of its cell.
My rule: use a real minimum like 16rem only when the component is useless below it. Otherwise minmax(0, 1fr) and let the content wrap.
Try this on your card grid: open the Grid inspector, then swap auto-fit for auto-fill with only two cards and watch the empty tracks appear. Then paste a long URL into one card and compare 1fr with minmax(0, 1fr). The track overlay shows you whether the grid or the content is setting the width.
Lesson completed