
The Grid's Missing Half
Native masonry layout is finally landing in browsers, solving the staggered-column problem without the computational overhead of JavaScript or the complexity of nested flexbox hacks.
The Grid's Missing Half
CSS Grid has been gaslighting us for years. We were told it was the "end-all, be-all" of layout engines, and for 90% of use cases, it is. But the moment you try to build a Pinterest-style layout, the illusion shatters. You end up with these awkward, gaping white spaces because Grid is obsessed with rows. It demands that every item in a row respects the height of its tallest neighbor, creating a rigid horizontal line that ruins the aesthetic of staggered content.
For a decade, we’ve solved this with heavy JavaScript libraries like Masonry.js or bizarre CSS hacks involving column-count that break the natural reading order (left-to-right becomes top-to-bottom).
But the "missing half" of the Grid specification is finally materializing. It's called Native Masonry, and it’s about to make a lot of NPM packages obsolete.
The Row Problem
In a standard grid, items are locked into a coordinate system. If the item in row 1, col 1 is 400px tall, every other item in row 1 effectively starts their next line at the 401st pixel.
/* Standard Grid: The "Gap" Creator */
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}Even if the second item is only 100px tall, there's just... dead space beneath it. It’s a waste of prime digital real estate.
The Hero We Need: grid-template-rows: masonry
The solution is deceptively simple. Instead of defining row heights or letting them be auto, we tell the browser to stop caring about rows entirely.
.masonry-container {
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
/* The Magic Wand */
grid-template-rows: masonry;
}By setting grid-template-rows: masonry, you’re telling the layout engine: "Fill the columns normally, but if an item is shorter than its neighbor, just tuck the next item right underneath it." No gaps, no JS, no layout shifts when images load.
A Practical Example: The Image Gallery
Let's look at how this looks in a real-world scenario. Imagine a gallery where images have different aspect ratios.
<div class="gallery">
<div class="card short">1</div>
<div class="card tall">2</div>
<div class="card medium">3</div>
<div class="card tall">4</div>
<div class="card short">5</div>
</div>.gallery {
display: grid;
gap: 1.5rem;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: masonry;
}
.card {
background: #2dd4bf;
border-radius: 8px;
padding: 1rem;
color: white;
font-weight: bold;
}
.short { height: 150px; }
.medium { height: 250px; }
.tall { height: 400px; }In the old world, the second row would wait for the 400px "tall" card to finish. In the new world, the items in the other columns just slide up. It’s fluid, it’s performant, and it keeps the DOM order intact for screen readers.
The "Masonry vs. Grid" Controversy
There is currently a bit of a spicy debate in the W3C and browser vendor circles.
Apple (Safari) and Mozilla (Firefox) have been shipping implementations using the grid-template-rows: masonry syntax. They argue masonry is just a subset of grid.
Google (Chrome/Chromium), however, recently proposed that masonry should be its own thing: display: masonry;. Their argument? Grid is already the most complex part of the CSS engine, and adding masonry logic to it makes it even more of a headache to maintain.
I’m personally leaning toward the grid-template-rows approach. It feels more intuitive to use existing grid tools (like grid-column: span 2) within a masonry context. If we switch to a completely different display type, we might lose some of that power.
Can You Use It Now?
The short answer: Not for production... yet.
As of mid-2024, it’s behind a flag.
- In Firefox, go to about:config and enable layout.css.grid-template-rows-masonry.enabled.
- In Safari Technology Preview, it's usually available for testing.
- In Chrome, they are still deep in the prototyping phase.
If you need a fallback today, you can use @supports to detect it, while providing a standard grid or a flexbox columns hack for older browsers.
.container {
display: flex;
flex-wrap: wrap; /* Fallback */
}
@supports (grid-template-rows: masonry) {
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry;
}
}Why This Matters
Beyond just "making things look like Pinterest," native masonry is a huge win for performance. Every time you use a JavaScript library to calculate positions, you’re forcing the browser to perform expensive "re-flows." On a page with hundreds of items, this can make scrolling feel janky, especially on low-end mobile devices.
Moving this logic into the browser’s C++ engine means it’s handled at the same level as standard layout, freeing up the main thread for more important things—like your actual application logic.
The grid is finally growing up. It's time we stop fighting the boxes and let the content flow where it actually wants to go.


