Flexible · Chapter 6 of 7 · 1 unit

The fr Unit

Not a length at all: a share of whatever is left.

fr is the odd one out. Every other unit in this guide resolves to a length: pixels, eventually. fr doesn’t. It’s a flexible length that only means anything inside CSS Grid, and it represents a share of the leftover space rather than a fixed measurement.Its spec type is <flex>, and fr is the only unit in it. Angles, times and resolutions have their own types too — but they measure quantities. <flex> exists to express a proportion, which is why it can’t mix with lengths.

1fr = one fraction of the free space in the grid container

The word that matters is leftover. fr is computed last, after fixed tracks, gaps, and content-based minimums have already taken their space. Whatever remains is divided among the fr tracks in proportion to their values.

Demo — How fr distributes leftover space
A
B
Content_that_is_quite_long
Computed track widths

Every fr track shares the space left after fixed tracks, gaps, and content minimums are removed. Try 200px 1fr — the1fr track takes everything except the fixed 200px.


fr

Formula
1fr = one share of the grid's remaining free space
Relative to
Leftover space after fixed tracks, gaps, and content minimums
Support
Universal

Consider three equal columns:

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

The container width is split into three equal shares — each track is one-third.

Change the proportions and the shares re-weight:

grid-template-columns: 1fr 2fr 1fr;

Now there are 1 + 2 + 1 = 4 shares. The middle track gets 2/4 (half the width); the outer tracks get 1/4 each.

Mix fixed and flexible tracks, and the fixed ones are removed first:

grid-template-columns: 200px 1fr;

The fixed 200px (plus any gap) is subtracted, and the single 1fr track takes all the remaining space. This is the canonical sidebar-plus-content layout.

Use when
  • Proportional column/row layouts: 1fr 2fr
  • Sidebar + content: 200px 1fr or 240px 1fr
  • Equal-width tracks: repeat(3, 1fr)
  • Filling remaining space after fixed tracks are placed
  • Combining with minmax() and repeat(auto-fit, …) for fluid grids
Avoid when
  • Outside Grid — fr is invalid in width, flex-basis, etc.
  • When you actually want content-based sizing — use auto or min-content
  • Assuming bare 1fr can shrink below its content — it has an implicit auto minimum

The minmax(0, 1fr) trap

This is the single most common fr gotcha, and it causes mysterious overflow.

A bare 1fr is not minmax(0, 1fr). It’s effectively minmax(auto, 1fr). That auto minimum means the track will not shrink below the size of its content. So if a grid item contains something that can’t shrink (a long unbroken string, an image with intrinsic width, a white-space: nowrap element), the track refuses to go below that minimum, and the grid blows out of its container.

/* Can overflow: the fr track won't shrink below its content */
.grid {
  grid-template-columns: 1fr 1fr;
}

The fix is to give the track a real zero minimum:

/* Allows the track to shrink below content size */
.grid {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

In the demo above, compare the 1fr 1fr 1fr template (long content forces the track wide) with minmax(0, 1fr) 1fr (the minmax track shrinks and ellipsizes).

fr can’t go inside calc()

fr is a flexible length, not a regular one, so it can’t be mixed with ordinary lengths in calc():

/* Invalid — fr is not allowed in calc() */
grid-template-columns: calc(1fr - 2em);

If you need “flexible track, minus some fixed space,” that’s what the track list itself is for: put the fixed amount in its own track or use minmax():

/* Do this instead */
grid-template-columns: 2em 1fr;          /* fixed gutter + flexible track */
grid-template-columns: minmax(0, 1fr);   /* flexible, allowed to shrink */

fr can sit alongside fixed lengths in the same track list, though: 250px repeat(12, 1fr) is perfectly valid; the flexible tracks just divide whatever the fixed 250px leaves behind.


fr is not flex-grow

fr and flex-grow feel similar (both distribute extra space proportionally), but they resolve differently, and conflating them leads to surprises.

  • flex-grow distributes only the extra space, and it does so on top of each item’s flex-basis (which defaults to the content size). Two items with flex-grow: 1 but different content can end up different widths: each keeps its content-based starting size and only the leftover space is shared equally, so unequal content yields unequal totals.
  • fr distributes the track space itself. Two 1fr tracks are equal regardless of content (assuming the auto minimum doesn’t intervene), because fr sizes the track, not the growth-beyond-basis.
/* Flexbox: items can end up unequal — growth adds to each item's content basis */
.flex { display: flex; }
.flex > * { flex-grow: 1; }   /* basis stays auto → wider content keeps a wider item */

/* Grid: tracks are genuinely equal shares of the container */
.grid { display: grid; grid-template-columns: 1fr 1fr; }

(Note that flex: 1 is the equalizing case: its shorthand sets flex-basis: 0%, which is exactly what removes the content-based difference. Plain flex-grow: 1 is what exposes the inequality.)

A useful way to hold it:

flex-grow answers “how should the extra space be shared?” fr answers “how should the whole space be divided into tracks?” That’s why fr lives in Grid and not in Flexbox — Grid defines explicit tracks; Flexbox grows items.


Why fr only exists in Grid

fr needs a defined set of tracks to divide space among. Grid provides exactly that — an explicit track list in grid-template-columns / grid-template-rows. Flexbox has no track list; it has items that flex along a single axis, so it uses flex-grow/flex-shrink/flex-basis instead. That’s why fr is valid across Grid’s track-sizing properties — grid-template-columns/-rows, the grid-auto-columns/-rows that size implicit tracks, and the grid/grid-template shorthands — and nowhere outside Grid.


Compact reference

fr
Meaning one share of the grid’s leftover free space
Computed after fixed tracks, gaps, and content minimums are subtracted
Valid in grid-template-columns / -rows, grid-auto-columns / -rows, and the grid / grid-template shorthands (incl. repeat() and minmax())
Invalid in width, flex-basis, gap, calc() — anything expecting a length
Pattern Result
1fr = minmax(auto, 1fr) — implicit auto minimum, can overflow
minmax(0, 1fr) lets the track shrink below its content
1fr 2fr 1fr shares 1 : 2 : 1 → 25% / 50% / 25%
200px 1fr fixed track is removed first; fr takes the rest

And the sibling concept: flex-grow distributes the extra space on top of each item’s flex-basis (content-aware), while fr divides the whole track space into shares (track-based).


Sources