By Tim King · Updated
CSS Masonry Grid Generator
Pinterest-Style Masonry Layout With CSS Columns or Grid-Row Span
OneTask is free, with no sign-up, and built by one person.
If this tool saved you time, a coffee helps keep new ones coming.
How the Masonry Grid Builder works
This CSS masonry grid generator builds a Pinterest-style layout. A masonry layout packs items of different heights into columns with no ragged gaps, the way Pinterest does. There are two ways to get close to it in CSS alone; this tool builds both, lets you compare them with your own column count and spacing, and hands you the code.
Masonry is the layout Pinterest made famous: items of different heights packed into columns with no ragged gaps, like bricks in a wall. It suits image galleries, portfolios, testimonials, product boards and card feeds, anywhere the content has natural heights that a regular grid would force into equal rows and pad with empty space. A normal CSS grid lines items up in rows, so a short card next to a tall one leaves a hole beneath it. Masonry lets each column stack independently and fills that hole.
Two ways to build a CSS masonry grid
True masonry, where each new item drops into whichever column is currently shortest, is only now arriving in browsers. After years of debate the CSS Working Group settled on a syntax in 2025, and support is still limited to preview builds, so check current support before relying on it. Until it ships everywhere, two pure-CSS techniques cover most needs, and choosing between them comes down to one question: does reading order matter?
CSS columns. Setting columns: 3 turns the container into a newspaper layout. Items flow
down the first column until it is full, then continue at the top of the second. Each item gets
break-inside: avoid so it is never split between columns, and a bottom margin equal to the
gap supplies the vertical spacing. The result looks like perfect masonry with three lines of
CSS and handles items of any height without measuring anything.
The catch is order. Item 2 sits under item 1, not beside it, so the sequence runs down each column, then across. For a photo gallery or a wall of testimonials nobody notices. For a chronological feed, a ranked list or anything a keyboard user tabs through, the order is confusing, because tab order follows the source, not the visual row.
Grid row spans. The container is a normal CSS grid with very short rows, 10 px here, and each item spans as many rows as its height needs. Items fill left to right in source order, which fixes the reading problem, and the gaps are real grid gaps. The cost is that every item must know its span in advance.
The row span formula
With a row unit of 10 px and a gap of g, an item of height h spans:
span = round((h + g) ÷ (10 + g))
Each row brings its own gap with it, which is why the gap appears on both sides. With a 16 px
gap, a 180 px item spans round(196 ÷ 26) = 8 rows, occupying 8 × 10 + 7 × 16 = 192 px. The
rounding error is always less than half a row plus gap, which is invisible in a card layout.
The generated code hard-codes the span for each sample item. In production you calculate it in
JavaScript from each item's rendered height, or from the image's aspect ratio if you know its
dimensions, and set grid-row: span N inline.
A smaller row unit reduces rounding but makes the browser create thousands of implicit rows on a long page. A larger one makes the bottom edges visibly stepped. Ten pixels is a practical middle.
How to read the generated code
.masonryis the container. With CSS columns it carriescolumnsandcolumn-gap; with grid row spans it carriesdisplay: grid, the column template,grid-auto-rows: 10pxandgap..masonry-itemholds the tile styling from your colour, border and radius choices. In the columns version it also carriesbreak-inside: avoidand the bottom margin.nth-child(4n + 1)colours every fourth tile, starting with the first, in the accent colour so you can see where items land as you change the column count. Delete it, or keep it for featured content.- The numbered
nth-childrules set each sample item's height or span. Replace them with your real content, which will size itself in the columns version. - The media query drops to two columns below 600 px.
Tips and pitfalls
- Let columns size themselves. In the columns version, replace
columns: 3withcolumn-width: 240pxand the browser fits as many columns as the width allows, with no media query needed. - Reserve image space. Set
widthandheightattributes, oraspect-ratio, on images. Otherwise every item starts at zero height, the layout jumps as images load, and row spans calculated too early are wrong. - Recalculate on resize. In the grid version, item heights change when the column width
changes, so recompute spans with a
ResizeObserver, not just once on load. - Mind lazy loading and infinite scroll. With CSS columns, adding items reflows every column, so earlier items move. The grid version appends at the bottom without moving what is already there.
- Keep the gap consistent. Columns use
column-gaphorizontally and the item margin vertically. Set both to the same value, as the generated code does, or the spacing looks uneven. - Consider a bento grid. If you control the sizes of every tile, a bento grid with fixed spans gives a more deliberate, magazine-style layout. For the basics of grid columns, gaps and spans, see the CSS grid generator.
When native masonry arrives
Native masonry will make the row-span method unnecessary: the browser will place each item in the shortest column itself, in source order, with no JavaScript. CSS columns will stay useful for text-heavy content where reading down columns is the intended pattern. Because both generated versions are plain CSS, they will keep working as a fallback in older browsers.
FAQ
Which method should I use?
Use CSS columns when items are visually independent — photos, quotes, product tiles — and their order does not need to read left to right. Use grid row spans when order matters or items need to align to a baseline grid, and be prepared to compute the span for each item.
Why are my items in the wrong order with CSS columns?
Because multi-column layout fills each column top to bottom before moving right, like a newspaper. That is inherent to the method. If you need left-to-right order, switch to the grid row span method, which places items in source order.
How do I calculate the row span for real content?
Measure the item's rendered height, add the gap, divide by the row unit plus the gap, and round
up. In JavaScript that is
Math.ceil((el.offsetHeight + gap) / (rowUnit + gap)), applied to grid-row-end as
span N. For images with known dimensions you can compute it from the aspect ratio instead.
Can I use images instead of coloured tiles?
Yes. Put an <img> inside each item with width: 100%; height: auto; display: block;. With the
columns method the item takes the image's natural height automatically. With the grid method,
set the span from the image's aspect ratio or measure it after load.
Is there a native CSS masonry property?
It is being standardised as grid-template-rows: masonry and ships in Firefox behind a flag and
in Safari Technology Preview. It is not yet safe for production, which is why both of these
fallbacks still matter. When it is widely supported it will replace the row-span method directly.
See also: all Layout & Spacing tools, Shadows & Motion, Shapes & SVG, UI Components, Forms & Inputs, Colour.
Related tools
Bento Grid Builder
Bento-box grid layouts with spanning tiles, copy-ready.
Breakpoint Helper
Media query and container query boilerplate from a breakpoint.
:has() Selector Builder
Pick a :has() pattern, see it work live and copy the HTML and CSS.
Cascade Layers Generator
Set your @layer order and get the blocks or imports to paste.
0–60 Calculator
0–60 mph, 0–100 km/h and quarter mile from power and weight.