The fr unit and the minmax() function are what make CSS Grid tracks genuinely flexible instead of fixed-width. Once you understand what each one actually means, grid layouts that adapt to their content and their container stop feeling like guesswork.

fr stands for "fraction" — it describes a share of whatever space is left over after fixed-size tracks have taken what they need. minmax() sets a track's lower and upper bound, so a track can grow but never shrink past a size you choose.

Understanding the fr Unit

A grid with three equal 1fr columns splits the available space evenly, because each column is getting one equal "fraction" of it.

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1rem;
}

This renders three columns of exactly equal width, and they resize automatically as the container resizes — no percentages or fixed pixel widths to maintain. Fractions don't have to be equal either:

.grid {
  display: grid;
  grid-template-columns: 250px 1fr 2fr;
  gap: 1rem;
}

Here the first column is a fixed 250px sidebar, and the remaining space is split between the second and third columns in a 1:2 ratio — the third column ends up twice as wide as the second.

Bounding a Track with minmax()

minmax(min, max) lets a track grow to fill available space, but never below (or above) the limits you set. This is especially useful combined with fr, since a plain fr column can shrink all the way down to nothing on a very narrow screen.

.grid {
  display: grid;
  grid-template-columns: minmax(150px, 1fr) minmax(150px, 1fr);
  gap: 1rem;
}

Each column now shares the space equally like before, but neither one will ever shrink below 150px — if the container gets too narrow to fit both at 150px, the grid will overflow or wrap instead of squashing the content unreadably thin.

Combining with repeat() and auto-fit

The real power shows up when minmax() is combined with repeat() and the keyword auto-fit — this single line creates a fully responsive grid with zero media queries:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
}

The browser fits as many 200px-minimum columns as will comfortably sit side by side, then stretches them evenly (1fr) to fill any remaining space. Resize the container and the number of columns recalculates automatically. This exact pattern is covered in more depth in responsive grids without media queries.

Together, fr and minmax() are the two building blocks behind almost every modern, no-media-query-needed grid layout — fr distributes leftover space proportionally, and minmax() keeps that distribution from ever going too far in either direction.