CSS Grid Generator

Once a layout has a header, a sidebar, a content column and a footer, naming the areas costs less than counting grid lines and survives being edited by someone else. Type the map as text and the generator checks that every area is a rectangle before you paste it.

1 to 12
Ignored when an area map is given — the map decides
Used by the fixed and minmax options
Leave empty for an unnamed grid. Repeating a name across adjacent cells merges them into one area.
At or below this width the media query collapses everything to one column
CSS Grid Generator — grid-template Columns, Rows and Named AreasBuildFigure

Tracks first, then placement

An element with display: grid defines column and row tracks with grid-template-columns and grid-template-rows, and its children fill those cells in source order unless you place them explicitly. repeat(3, 1fr) is shorthand for 1fr 1fr 1fr, and fr distributes whatever space is left after fixed tracks and gaps are subtracted.

gap only puts space between tracks, never around the outside, which removes the whole class of first-child and last-child margin exceptions that flexbox layouts used to need. The distinction between grid and flexbox is often overstated — either can do a row of cards — but a page skeleton with a header, a sidebar, a content column and a footer is a two-dimensional problem, and that is where grid stops being a preference and starts being the shorter code.

Named areas

grid-template-areas takes one quoted string per row with a name in each cell. Adjacent cells sharing a name merge into a single area, a dot marks an empty cell, and each child needs only grid-area: name — no line numbers anywhere. The layout becomes readable as ASCII art in the stylesheet, which is a real maintenance advantage six months later.

One rule governs everything: cells with the same name must form a rectangle. An L-shaped area is invalid, and the browser does not partially apply it — it throws out the entire grid-template-areas declaration, so the symptom is a layout that collapses to default flow with no error in the console. The generator checks each area and warns before you paste it.

The payoff arrives at the breakpoint. Because placement is by name rather than by source position, you can restate the area map inside a media query and completely rearrange the page — sidebar above the content on mobile, below it on desktop — without touching the HTML or introducing a tab-order mismatch. Reordering via order or explicit line placement does change the visual order away from the DOM order, which is a documented accessibility hazard; the area map avoids it only when you keep the reading order sensible in the source.

Choosing column sizing

1fr is not quite equal columns. An fr track has an automatic minimum size, so a cell containing a long unbreakable string can push its column wider than its neighbours. minmax(0, 1fr) is the genuinely equal version, and it is the fix for the classic complaint that one grid column refuses to shrink.

auto sizes to content, which suits a fixed-width sidebar paired with an fr content column. Fixed px is for when a track really must be a specific width. minmax(200px, 1fr) guarantees a floor and shares the remainder, and combined with repeat(auto-fill, …) or repeat(auto-fit, …) it produces a card grid whose column count changes with the viewport and needs no media query at all. This tool emits a fixed column count; swap repeat(3, …) for repeat(auto-fit, minmax(200px, 1fr)) in the output to get the responsive version.

What the media query does and does not cover

The emitted @media (max-width: …) block is deliberately the simplest possible thing: one column, auto rows, areas stacked in the order they were first named. Real projects usually want a tablet step in between, and often want a different stacking order than the desktop reading order — promoting a summary panel above the main content, for instance. Both are edits to the area strings rather than structural changes.

Rows go to auto in that block for a specific reason. A fixed row height that was comfortable in a three-column layout will clip content once everything is stacked into one narrow column, and the overflow is silent. If you need a minimum instead, minmax(120px, auto) gives you the floor without the clipping.

Treat what comes out of here as a skeleton to start from. It gets the track definitions and the area syntax right, which is the part that is fiddly to type; the decisions about where the breakpoints belong and what the page is actually for are still yours.

Questions people ask

Why is my grid-template-areas declaration being ignored?

Almost always because one area is not rectangular, or because the rows have different cell counts. Both make the value invalid, and CSS discards an invalid declaration entirely rather than partially applying it — so the grid falls back to whatever the columns and rows say and the areas do nothing. Check that every row string has the same number of tokens and that each repeated name traces a solid rectangle. The generator flags both cases.

My items are overflowing the grid or spilling into extra rows.

If there are more children than explicit cells, grid creates implicit rows to hold them — control their height with grid-auto-rows, or match the child count to columns times rows. If a single item is stretching its track, the cause is usually a long unbreakable string: an fr track has an auto minimum, so set minmax(0, 1fr) on the columns or min-width: 0 on the item.

When should I use flexbox instead?

Flexbox distributes items along one axis and lets their content decide the sizes; grid defines the tracks up front and places items into them. A toolbar, a row of tags, or anything where the item count is unknown and the sizing should follow the content is flexbox work. A page skeleton, a form with aligned label and field columns, or any layout where things must line up across rows as well as along them is grid work. Nesting one inside the other is normal and not a compromise.

Can I use rem for the gap instead of px?

Yes — change the value in the output. A rem gap scales with the root font size, so the spacing grows for someone reading at a larger default text size, which usually looks better than text that has grown inside spacing that has not. Percentage gaps also work and resolve against the content box in the corresponding axis.

Related