Masonry layout, on the web, is when items of an uneven size are laid out such that there aren’t uneven gaps. I would guess the term was coined (or at least popularized) for the web by David DeSandro because of his popular Masonry JavaScript library, which has been around since 2010.
JavaScript library. Nothing against JavaScript, but it’s understandable we might not want to lean on it for doing layout. Is there anything we can do in CSS directly these days? Sorta.
Is vertical order with ragged bottoms OK?
If it is, then CSS columns will do just fine.
Flexbox can do vertical columns with ragged endings too
But it’s not quite as clever, because you’ll need to set a height of some kind to get it to wrap the columns. You’ll also have to be explicit about widths rather than having it decide columns for you.
But it’s doable and it does auto space the gaps if there is room.
Do you need a clean bottom edge? A Flexbox/JavaScript combo can help.
Jamie Perkins originally wrote this, then Janosh Riebesell re-wrote it and, now I’m porting it here.
It totally messes with the order and requires the children to be flexy about their height, but it does the trick:
Is horizontal line masonry OK?
If it’s just the uneven brick-like look you’re after, then horizontal masonry is way easier. You could probably even float stuff if you don’t care about the ragged edge. If you wanna keep it a block… flexbox with allowed flex-grow
is the ticket.
You’d think CSS grid could help
CSS grid is very amazing and useful in a CSS developer’s everyday life, but it’s not really designed for masonry style layouts. CSS grid is about defining lines and placing things along those lines, where masonry is about letting elements end where they may, but still exerting some positional influence.
Balázs Sziklai has a nice example of auto-flowing grids that all stack together nicely, with pretty good horiziontal ordering:
But you can see how strict the lines are. There is a way though!
Grid + JavaScript-manipulated row spans
Andy Barefoot wrote up a great guide. The trick is setting up repeating grid rows that are fairly short, letting the elements fall into the grid horizontally as they may, then adjusting their heights to match the grid with some fairly light math to calculate how many rows they should span.
Rahul Arora went down this road as well:
Both of these are pretty cool in that the DOM order and visual order are sensical.
Order-shifted elements in a Flexbox layout
Normally when you think of using order
to move things around in a flexbox or grid layout, you’re in dangerous territory, as tab order will likely follow the DOM order, which no longer matches the expected tabbing order because visually things have moved all around. In this demo by Diederik van Leeuwen, order
is used to make what starts out as a column-oriented flexbox but manipulated into being horizontally ordered with some clever JavaScript.
DOM-shifted elements in a CSS columns layout
What people generally want is column-stacking (varied heights on elements), but with horizontal ordering. That last grid demo above handles it pretty well, but it’s not the only way.
Jesse Korzan tackled it with CSS columns. It needs JavaScript as well to get it done. In this case, it shifts the elements in the DOM to order them left-to-right while providing a horizontal stack using a CSS columns layout. This introduces a bit of an accessibility problem since the visual order (left-to-right) and source order (top-to-bottom) are super different & dash; though perhaps fixable with programmatic tabindex
?
There’s also the original library and variations
Float away, my pretties.
And it’s newer, hipper verion: Colcade!
And here’s MagicGrid, in which a flexbox layout is lightly manipulated with a JavaScript lib:
CSS Houdini!
Houdini is broken up into different APIs that are all shipping at different times. The Paint and Typed OM APIs are the furthest along, but there is some support for the Layout API, which is incredibly exciting as it unlocks possibilities like masonry layout.flex-gro
Here’s a demo from Google:
Great article, Chris! The latest grid-related challenge I’ve had on my desk is a use case where the mobile order needs to differ from the desktop layout, but you want to keep your content in order of importance in the DOM.
I challenged myself to use only CSS (had to touch it off with a one-liner in JS for the final product).
I wrote a post on my solution here: http://joshpalmeri.com/blog/2018/10/01/complex-layouts-with-css-grid-or-flexbox-or-neither-2/
Would love to know your thoughts!
-Josh
I like the original masonry library, but it looks like when element wrap, the columns don’t expand to fill the vacant space. Any workarounds for that?
The “messes with the order” example isn’t due to it being Flexbox or Masonry or anything. For some reason, the JS code just shuffles the order of the children (by giving them an
order
property value equal to their index mod 3). Note that it counts up 1, 4, 7, 10, 13, then back down to 2, 5, 8, 11, etc. I have no idea why it does this; the heights are already random, so it’s not like it helps balance them or anything.The “Grid, with dense auto-placement” is my favorite technique, and I wish we could make it work a little better with the “small row” height version. Ultimately, tho, that probably needs to be handled as something separate from Grid that just builds on the same concepts.
Great round up! Colcade should also get a plug (Another of DeSandro’s crazy creations.)
As he puts it:
Example, forked from the ones in this post:
PS. love the new site! Knocked it outa the park with all the detail. Think I just found the one thing to slip through the cracks tho. Links in comments (at least in preview) look great on hover but are indistinguishable otherwise. Needs a thin orange>pink gradient underline or something :)
There’s also CSS multi-col, Rachel Andrew wrote an in-depth article about it (https://www.smashingmagazine.com/2019/01/css-multiple-column-layout-multicol/) which also covers a bit about the masonry layout.
Yeah! Super useful. It’s the first demo in this article.
React spring is pretty neat:
https://codesandbox.io/embed/26mjowzpr
I recently developed a masonry site for a client using https://packery.metafizzy.co. This was very helpful for reodering and then storing and retrieving the order.
There’s also a Vue.js version of Magic Grid: https://github.com/imlinus/Vue-Magic-Grid
I encountered some issues with the original Masonry last year when filling the grid with images of varying widths and heights. I wrote about these issues and how to get around them in React here https://www.damiannicholson.com/posts/2018/07/14/creating-a-layout-like-pinterest-with-react-and-the-partition-problem/ as you want the images to be densely packed, with a clean bottom edge whilst also retaining image aspect ratios(i.e. no image stretching).
Hello there. I am almost every second project in demand for masonry layout styling. I recently found out this small rewrite on masonry, which is really small js, in combination with flexbox. If anyone is interested, check it out
https://columnsjs.com
It works on ie as well as on all other modern browser.
Cheers
https://github.com/paulcollett/vue-masonry-css
From Guido Jansen:
A grid based on single pixels weirds me out a bit. Doesn’t seem like it could be particularly performant, especially with the
resize
handler on the window, but it certainly is clever.