Skip to content

CSS Grid Generator

Set the columns, rows and gaps, drag across the grid to place items, then copy the HTML and CSS. Export with named areas or line numbers, as plain CSS or Tailwind classes, and optionally stack everything into one column on phones.

  1. Pick a starting layout or set the column and row count.
  2. Type a size for each track: 1fr, 200px, auto, minmax(…).
  3. Drag across empty cells to add an item; drag it to move, use its corner to resize.
  4. Name the items, choose the export style and copy the code.

Grid

Box — wide · columns — px · rows — pxDrag the corner of the box to test other widths.
Code style
Item placement
px
HTML
<div class="layout">
</div>
CSS
.layout {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, minmax(100px, auto));
  gap: 16px;
}

Items are written top to bottom, left to right. That is the order screen readers and the keyboard follow, and the order they stack in on phones.

Track sizes: fr, px, auto and minmax()

Each box under Columns and Rows is one track. The browser sizes fixed tracks first (px, rem, %), then content-sized ones (auto, min-content, max-content), and only then splits whatever space is left between the fr tracks. That order is why mixing them works: 250px 1fr always gives the sidebar exactly 250px and the content everything else.

CSS grid track size values and what they do
ValueSize of the trackTypical use
200px, 12remExactly that lengthSidebars, icon columns
25%Share of the container, before gaps are taken offRarely needed; fr handles gaps for you
1fr, 2frShare of the leftover space, after gaps and fixed tracksMain content, equal columns
autoFits the content, then stretches into spare space if no fr track takes itHeader and footer rows
min-contentAs narrow as the content can wrap (the longest word)Label columns
max-contentAs wide as the content without wrappingShort buttons, tags
minmax(0, 1fr)A flexible share that is allowed to shrink to 0Columns holding code, tables, long URLs
minmax(100px, auto)At least 100px, taller if the content needs itCard rows that should not collapse
fit-content(300px)Like auto, but never wider than 300pxA column that hugs short content

When every track in a list is the same, the export shortens it: four 1fr columns become repeat(4, 1fr). The two forms are identical to the browser.

Worked example: what 1fr works out to

Load the Holy Grail layout and drag the preview box to about 1,000px wide. Its columns are 200px minmax(0, 1fr) 200px with a 16px gap. The two gaps sit between three columns, so:

1000 − 200 − 200 − (2 × 16) = 568px for the middle column

The line under the preview reads the sizes back from the browser, so you can check this against the real figure as you resize. Now try the same layout with percentages, 20% 60% 20%. The columns add up to 100% of 1,000px, then the browser adds the 32px of gaps on top, and the grid is 1,032px wide in a 1,000px box: a horizontal scrollbar. With fr, the gaps come out first and the columns share what is left, so the total always fits.

Rows work the same way only if the container has a height to share. Holy Grail turns on min-height: 100vh, so its middle 1fr row gets the screen height minus the header, footer and gaps. Without that line, a 1fr row just shrinks to fit its content.

Named areas or line numbers

Grid lines are numbered from 1 at the start edge, so a three-column grid has lines 1 to 4. grid-column: 1 / 4 means "from line 1 to line 4", the full width. Named areas describe the same placement as a picture instead:

grid-template-areas:
  "header header  header"
  "nav    content sidebar"
  "footer footer  footer";

Each quoted string is one row and each word is one cell. Repeating a name across cells merges them, and a . leaves a cell empty. The generator pads the names so the columns line up, which the browser ignores but people reading the code will not.

Named areas compared with line-number placement
Named areasLine numbers
ReadabilityThe CSS shows the layout as a mapNeeds counting to picture
Rearranging at a breakpointRewrite one grid-template-areas valueChange every item's lines
Shapes allowedRectangles only, no overlapsItems can overlap on purpose
Many small itemsOne name each gets longCompact
TailwindAwkward in class namescol-[1_/_3] row-[2_/_3]

Area names are custom identifiers, so they cannot start with a digit and cannot be auto, span or a CSS-wide keyword such as inherit. The name field rejects those.

A misspelled name does not raise an error, and it does not put the item back in the normal flow either. If an item says grid-area: site-header and no area has that name, the browser looks for lines called site-header-start, finds none, and the specification says to treat every implicit line as having that name. So the item lands in a new row and column just outside the grid, usually bottom-right, and the layout grows an extra track. If one block suddenly appears in a corner after a rename, compare the class's grid-area with the template first.

Making the grid responsive

The tracks you set do not shrink below their fixed sizes: a 200px + 1fr + 200px layout with 16px gaps needs more than 432px before the middle column has any room. Tick "One column below" and the export becomes mobile-first: the container is a plain one-column grid by default, and the full template and item placement only apply inside @media (min-width: …). On a phone the items stack in source order, which is why the HTML is always written top to bottom, left to right.

For a run of cards, where the number of columns should depend on the space, skip the media query entirely. This is the one-line pattern, with a live demo:

Keyword
Card 1
Card 2
Card 3

Drag the bottom-right corner of the dashed box to narrow it and watch the cards wrap.

CSS
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
  gap: 16px;
}

auto-fill creates as many columns as fit at the minimum width, even when there are not enough cards to fill them. With three cards in a row wide enough for five, the cards keep their width and two empty tracks sit at the end. auto-fit collapses those empty tracks to zero, so the same three cards stretch across the full row. Set the sample to 2 cards and switch between the two to see it; once the row is full, they behave the same.

min(240px, 100%) handles the other edge: on a screen narrower than 240px, a plain minmax(240px, 1fr) still insists on 240px and the page scrolls sideways. Taking the smaller of the two lets the single column shrink with the screen.

Masonry and display: grid-lanes

A Pinterest-style layout, where each tile is as tall as its content and the next tile tucks under the shortest column, is not something a normal grid does: every item in a row shares the row's height. The CSS Working Group's answer is a new display type, display: grid-lanes, in the CSS Grid Layout Level 3 draft. It replaced the earlier grid-template-rows: masonry proposal. Safari 26.4 ships it; Chrome, Edge and Firefox have experimental versions behind flags at the time of writing, so treat it as an enhancement over a normal grid:

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
}

@supports (display: grid-lanes) {
  .gallery { display: grid-lanes; }
}

The older workaround sets tiny rows, such as grid-auto-rows: 10px, and gives each tile a row span. It works everywhere, but the gap catches people out because it sits between every pair of rows the tile crosses. A tile spanning 15 rows with a 16px row gap is not 150px tall:

15 × 10px + 14 × 16px = 150 + 224 = 374px

The usual fix is row-gap: 0 with 1px rows, spacing the tiles with margins instead, so a tile's span equals its height in pixels. A few lines of JavaScript then measure each tile's content and set grid-row: span … to match.

Grid or Flexbox?

When to use CSS Grid and when to use Flexbox
SituationBetter fitWhy
Page shell: header, sidebar, main, footerGridRows and columns are planned together
A row of buttons or tagsFlexboxItems size to their content in one direction
Cards that should line up in both directionsGridEach row shares column widths
Navigation bar with a logo pushed leftFlexboxmargin-left: auto on one item
Last row of cards should not stretchGridFlex-wrap stretches leftovers unless you fix widths
Centring one thingEitherplace-items: center or justify/align on flex

Most pages use both: Grid for the outer layout this generator builds, and Flexbox inside each area for the content that runs in a line.

When the layout does not behave

Common CSS grid problems and fixes
SymptomCauseFix
A 1fr column pushes past the screen1fr means minmax(auto, 1fr), and auto will not go below the longest word, URL or code lineUse minmax(0, 1fr), as the presets do
fr rows are all the same small heightThe container has no height to shareGive it min-height (or height), or use auto rows
gap: 10px 20px spaces the wrong wayThe shorthand is row gap first, then column gapSwap them, or use row-gap and column-gap
An extra row or column appearsAn item is placed past the last line, or its area name is misspelledCheck grid-column/grid-row ends and area names
Items ignore the griddisplay: grid is on a wrapper, not the direct parentOnly direct children are grid items (or use subgrid)
100vh is too tall on phonesMobile address bars are not counted in vhUse min-height: 100dvh where supported

Frequently asked questions

Is grid-gap still valid?

Yes. grid-gap, grid-row-gap and grid-column-gap were renamed gap, row-gap and column-gap when the properties were extended to Flexbox and multi-column layout. Browsers keep the old names as aliases, but new code should use gap.

How do I make one item span the full width?

Use grid-column: 1 / -1. Negative numbers count from the end, so -1 is the last line of the explicit grid. In this tool, drag the item across every column or set its column span to the column count.

Can grid items overlap?

Yes, when placed by line numbers; give the one that should sit on top a higher z-index. Areas in one grid-template-areas map cannot overlap, though two items given the same grid-area will stack. This generator keeps items apart so both export styles stay valid.

What is subgrid?

grid-template-columns: subgrid lets a nested grid reuse its parent’s column lines, so content inside separate cards can line up. It has worked in Firefox, Safari and Chrome since 2023.

Does the order of items in the HTML matter?

For looks, no: placement decides where each item appears. For people, yes: screen readers and the Tab key follow the HTML order. The generator writes items in reading order, top to bottom and left to right.

Why use px for gaps and not %?

Percentage gaps resolve against the container width, and for row gaps against a height that is often not set. Fixed px or rem gaps are predictable, which is why the tool offers those two.

Sources