belun.app Blog
RU

CSS Grid in Practice: fr Units, Spans, and the Rules Worth Knowing

How grid tracks, the fr unit, gaps, and item spans really work, plus when grid beats flexbox and when it does not.

Web designer building a CSS grid layout on a laptop screen at a desk

The thing that finally made CSS Grid click for me was realising that 1fr doesn’t mean “one third”. It means “one share of what’s left over”. Those sound the same until you add a gap, and then one of them is wrong.

Try it. Three columns at 33.33% with a 20px gap between them overflows the container, because percentages are computed against the full width and know nothing about the 40px of gaps you added. repeat(3, 1fr) with the same gap fits exactly, because fr divides the space that remains after fixed sizes and gaps are subtracted. Every float-era hack for gutters existed because that subtraction used to be impossible.

Grid shipped in Chrome and Firefox within a week of each other in March 2017, which is unusual enough to be worth remembering. It’s been safe to use for years.

Sizing tracks

You get four everyday options, and they answer different questions:

  • fr — split the leftover space. Use it for the parts that should flex.
  • px — a fixed track. Sidebars, icon columns, anything that shouldn’t move.
  • % — a share of the container. Rarely what you want once gaps are involved.
  • auto — let the content decide. Handy for a label column that should be as wide as its longest label and no wider.

A layout like 240px 1fr is the classic app shell: fixed sidebar, content takes the rest. Mixing units freely is normal and not a code smell.

The CSS Grid Generator lets you set each track separately and watch the result. When every track ends up the same, the output collapses to repeat(n, size) — the shorter form most people write by hand.

Spans, and where people get stuck

grid-column: span 2 makes an item two tracks wide wherever the auto-placement algorithm puts it. grid-column: 2 / span 2 pins it to column line 2 and then spans two.

The confusion is that those numbers are lines, not columns. A three-column grid has four vertical lines: line 1 at the far left, line 4 at the far right. So grid-column: 1 / 4 spans the whole thing. Off-by-one errors here are basically a rite of passage.

Click any cell in the preview and you can set a start line, a span, or both, for columns and rows. Each item that differs from the default gets its own small rule in the output, and items you leave alone produce no code at all.

The alignment default that surprises everyone

justify-items and align-items both default to stretch. Items fill their cells completely, so a background colour on a grid child paints the entire cell rather than hugging the text. People sometimes spend twenty minutes hunting for the padding that isn’t there.

Set either to start, center, or end and the item shrinks to its content in that direction. That’s usually the fix.

Grid or flexbox?

Grid controls both axes; flexbox controls one. A dashboard, a page shell, an image gallery where things must line up in rows and columns: grid. A navbar, a button group, a row of tags that wraps: flexbox. Most real pages use both, and arguing about which is “better” is a bit like arguing whether a hammer beats a screwdriver.

One combination worth stealing: repeat(auto-fit, minmax(200px, 1fr)) gives you a responsive card grid with no media queries at all. It’s outside what the visual builder covers, but once you’ve seen the fr behaviour above, it reads naturally.

Build a layout in the CSS Grid Generator, copy the CSS, and skip the guessing. Everything runs in your browser — nothing is uploaded.

Try the tool

CSS Grid Generator →