How to use this Grid Generator
Adjust the number of columns and rows, then fine-tune the horizontal and vertical gaps.
The live preview updates automatically so you can see the result immediately. When the
layout looks right, copy the generated CSS and paste it into your project.
- Choose the number of columns.
- Choose the number of rows.
- Adjust column gap and row gap.
- Preview the layout live.
- Copy the generated CSS into your stylesheet or component.
What this tool generates
The generated output includes the core CSS Grid container rules:
display: grid, grid-template-columns,
grid-template-rows, column-gap, and
row-gap.
Common use cases
- Card layouts
- Gallery sections
- Dashboard widgets
- Responsive content blocks
- Landing page layouts
fr shares free space, not total space
The single most surprising thing about CSS Grid is that grid-template-columns: 1fr
1fr does not guarantee two equal columns. The fr unit
divides the leftover space after every other sizing constraint has been satisfied —
and one of those constraints is that a track will not shrink below the minimum size of its
content. Drop a long unbreakable string or a wide image into one of the two tracks and it
claims more than its share; the "equal" columns come out lopsided.
The reason is that 1fr is really minmax(auto, 1fr) under the hood,
and that auto minimum is the track's min-content size. The fix is to override the
minimum explicitly: grid-template-columns: minmax(0, 1fr) minmax(0, 1fr). With a
floor of 0 the tracks are free to be genuinely equal, and the overflowing content
is forced to wrap or scroll within its cell instead of stretching the column. This one line
resolves the overwhelming majority of "my grid columns are uneven" bug reports.
auto-fill vs auto-fit: the difference only shows sometimes
The responsive-grid idiom is
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)), and swapping
auto-fill for auto-fit looks like it does nothing — until the row is
wide enough to hold more tracks than you have items. That is the only situation where they
differ.
auto-fill keeps creating empty tracks to fill the width, so leftover space is
reserved as blank columns and your three cards stay 200px wide on a huge screen.
auto-fit creates the same tracks but then collapses the empty ones to zero,
letting the real items stretch to absorb the remaining space, so three cards spread edge to
edge. Choose auto-fit when you want items to grow and fill the row;
auto-fill when you want a consistent item size with space held for items that
might arrive later.
The implicit grid: rows you did not ask for
When you write grid-template-columns and grid-template-rows, you
define the explicit grid. But if you place more items than that grid has cells
— or position an item onto a line beyond it — Grid quietly manufactures extra tracks to hold
them. That is the implicit grid, and it is why a layout you sized for three
rows sometimes sprouts a mysterious fourth.
Implicit tracks are sized by grid-auto-rows and grid-auto-columns,
which default to auto — so the surprise rows collapse to content height rather
than matching your explicit rows. If your grid should keep growing uniformly, set
grid-auto-rows to the size you want (for example minmax(120px, auto)).
The direction new items flow is controlled by grid-auto-flow;
grid-auto-flow: dense lets Grid backfill earlier gaps, at the cost of possibly
reordering items away from source order.
Named areas and named lines
Grid can be addressed by name, which turns a layout into something you can read at a glance.
grid-template-areas lets you draw the layout as ASCII — each quoted string is a
row, each word a named cell — then place children with
grid-area: header. Repeat a name across cells and that area spans them; use a
. for an empty cell. Rearranging the layout at a breakpoint becomes a matter of
redrawing the strings inside a media query, with no changes to the child rules.
You can also name the lines between tracks, in square brackets inside the template:
grid-template-columns: [sidebar-start] 240px [sidebar-end content-start] 1fr
[content-end]. Items then reference grid-column: content-start / content-end
instead of counting numeric line indices, which stops the layout from silently breaking when
you insert or remove a track. Defining a named area also auto-creates matching
-start/-end line names, so the two systems interoperate.
Frequently Asked Questions
Why are my 1fr 1fr columns not equal width?
fr distributes only the free space left after content minimums are met, and
1fr behaves like minmax(auto, 1fr), so a track with large content
refuses to shrink. Use minmax(0, 1fr) for each track to force genuinely equal
columns and make the content wrap instead.
What is the difference between auto-fill and auto-fit?
They differ only when the row can hold more tracks than you have items.
auto-fill keeps the extra tracks empty (reserving the space), so items stay
their minimum size. auto-fit collapses empty tracks to zero, so the real items
stretch to fill the row.
Why does my grid have an extra row I did not define?
When items exceed the explicit grid, Grid auto-creates implicit tracks to hold them, sized
by grid-auto-rows (default auto). Set grid-auto-rows
to control those rows, or check whether an item was placed onto a line past your defined
tracks.
Should I use CSS Grid or Flexbox?
Use Grid when you need to control rows and columns together — page skeletons, card
galleries, dashboards. Use Flexbox for one-axis alignment like nav bars and button rows.
They compose: a grid cell can be a flex container and vice versa.
How do I make a responsive grid with no media queries?
Use repeat(auto-fit, minmax(200px, 1fr)) for the columns. Tracks are at least
200px and grow to share the row; the count adjusts to the container width automatically.
Swap auto-fit for auto-fill if you want empty space kept as blank
columns.
What are grid template areas?
grid-template-areas lets you name regions and draw the layout as rows of
quoted strings, then place children with grid-area: name. It is highly
readable and makes responsive re-layout as simple as redrawing the strings inside a media
query.