ESC

Type to search the knowledge base.

minmax and fr Units

Grid track sizing with fr free space and minmax() floors/ceilings — equal columns, fluid sidebars, and overflow-safe patterns.

intermediate3 min read
  • css
  • grid
  • minmax
  • fr

CSS Grid’s power track list is fr (fraction of free space) plus minmax(min, max) (clamp a track’s size). Together they replace most float/percentage column hacks and pair cleanly with auto-fit / auto-fill.

Docs: MDN fr, minmax(), track sizing.

fr distributes free space

.layout {
  display: grid;
  grid-template-columns: 1fr 2fr; /* second column twice the free space */
  gap: 1rem;
}

fr is not “percent of the container” after gaps in the naive sense — the browser resolves non-fr tracks first, then shares leftover space among fr tracks.

.layout {
  grid-template-columns: 200px 1fr 1fr; /* fixed rail + two equal flexible cols */
}

minmax

grid-template-columns: minmax(12rem, 20rem) minmax(0, 1fr);
  • Track 1 between 12rem and 20rem
  • Track 2 takes the rest, can shrink to 0 (with item min-size caveats)
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 1rem;
}

The min(100%, 16rem) floor prevents horizontal overflow when the container is narrower than 16rem.

Equal columns pattern

.equal {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

minmax(0, 1fr) is a classic fix: default auto minimums can stop 1fr tracks from shrinking, overflowing the grid. Same spirit as min-width: 0 on flex children.

Fluid sidebar

.shell {
  display: grid;
  grid-template-columns: minmax(12rem, 18rem) minmax(0, 1fr);
  gap: 1.5rem;
}

@media (max-width: 40rem) {
  .shell {
    grid-template-columns: minmax(0, 1fr);
  }
}

min-content / max-content / auto

grid-template-columns: max-content 1fr; /* label column as wide as longest label */
grid-template-columns: min-content 1fr; /* as narrow as possible without overflow if possible */
.form-grid {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 0.5rem 1rem;
  align-items: center;
}

Interview out-loud

“fr shares free space among tracks after fixed sizes and gaps are accounted for. minmax(min, max) clamps a track. I often write minmax(0, 1fr) to allow shrinking, and repeat(auto-fit, minmax(min(100%, N), 1fr)) for responsive card grids. fr is not a simple percentage synonym.”

Footguns

  1. 1fr tracks that won’t shrink because of content min-size — use minmax(0,1fr) / min-width:0 on items.
  2. Nested percentages + fr without tracing free space.
  3. Huge min in minmax causing overflow.
  4. Mixing too many auto tracks and wondering why fr got zero free space.
  5. Forgetting gap in mental math when counting “how many cards fit.”

Free space walkthrough

.grid {
  width: 1000px;
  display: grid;
  gap: 20px;
  grid-template-columns: 200px 1fr 2fr;
}

Gaps take 2 × 20 = 40px. Fixed track takes 200px. Free space ≈ 1000 - 200 - 40 = 760px. Then 1fr gets ~253px and 2fr ~507px. Mental math like this catches bugs when someone claims “fr means percent.”

auto tracks

grid-template-columns: auto 1fr auto;

auto sizes to content (with min/max constraints). Side action buttons stay content-sized; the middle field eats the rest. Add minmax(0, 1fr) on the flexible track if content overflow should scroll inside rather than blow the grid.

.form-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 0.5rem;
  align-items: center;
}

Further reading

Related guides