What you’re building here
A display: grid container, drawn instead of typed. You set how many columns and rows you want, pick the size of each track, dial in the gaps, and the preview redraws every cell as you go. The CSS at the bottom is the exact thing you paste into your stylesheet. No build step, no React, no framework baggage. Just the raw grid-template-columns, grid-template-rows, and gap lines.
Grid is one of those features that’s easy to half-understand. You know 1fr does something, but the difference between 1fr 1fr 1fr and repeat(3, 1fr) feels fuzzy until you see the boxes move. That’s the whole point of doing it visually.
The three units, in plain terms
Every track here uses one of three sizes:
- fr splits leftover space by ratio. Two columns of
1fr 1frare equal halves. Change one to2frand it takes two thirds. This is the unit you’ll reach for most. - px locks a track to a fixed width or height. Perfect for a
250pxsidebar that shouldn’t stretch. - auto sizes the track to fit its content. A nav column that’s exactly as wide as its longest link, no more.
Mix them freely. A classic app shell is 250px 1fr: fixed sidebar on the left, everything else fills the rest. Try the Sidebar preset to see it.
How to use it
Click a preset to start somewhere sensible, or build from scratch. Use the plus and minus buttons to add or drop columns and rows (up to 12 each). For any track, type a number and tap fr, px, or auto. Set the gap once if rows and columns share spacing, or untick the link box to control row gap and column gap separately.
The numbered boxes in the preview are your grid cells. Cell count is just columns times rows, so a 4-by-3 grid shows twelve. When the layout looks right, hit Copy or Download the .css file.
Good to know
gap replaced the old grid-gap years ago. Every browser people actually use supports the short version, so that’s what this outputs. If you’re supporting something ancient, swap gap for grid-gap by hand.
One thing the preview won’t show you: how content behaves when it overflows a fixed px track. Real text can blow past a 100px column. Test with your actual content before shipping. The generator gives you the skeleton, not the stress test.
Worth a mention: this builds the container, not the items. Placing a card so it spans two columns uses grid-column: span 2 on the child, which lives outside what this tool generates. Most layouts don’t need that, though. Equal tracks plus a gap covers a huge chunk of real-world grids.
Common questions
What’s the difference between fr and percent?
fr divides the space that’s left after gaps and fixed tracks are subtracted. Percentages don’t account for the gap, so 50% 50% plus a gap overflows the container. 1fr 1fr never does. Use fr.
Can I use repeat() instead of listing every track?
This tool writes out each track explicitly, like 1fr 1fr 1fr. That’s identical in effect to repeat(3, 1fr), just more verbose. Feel free to compress it by hand after copying if you prefer the shorter form.
Does this work for responsive layouts?
The output is a single fixed grid. For responsive behavior, wrap the generated CSS in a media query, or look into auto-fit with minmax() for grids that reflow on their own. This tool handles the static case.
Why are my columns uneven when they’re all 1fr?
Almost always it’s content forcing a track wider than its share. A long unbroken string or a fixed-width image inside a cell will stretch it. Add min-width: 0 to the grid items to let them shrink.
Is anything sent to a server? Nope. The CSS is built in your browser as you click. Nothing uploads, nothing’s stored.