Masonry, Item Flow, and… GULP?
Published 22 hours pastThere’s a layout type that web designers have been using for a long time now, and yet can’t be easily done with CSS: “masonry” layout, sometimes called “you know, like Pinterest does it” layout. Masonry sits sort of halfway between flexbox and grid layout, which is a big part of why it’s been so hard to formalize. There are those who think of it as an extension of flexbox, and others who think it’s an extension of grid, and both schools of thought have pretty solid cases.
So that’s been a lot of the discussion, which led to competing blog posts from Google (“Feedback needed: How should we define CSS masonry?”) and Apple (“Help us choose the final syntax for Masonry in CSS”). Brian and I, with special guest star Rachel Andrew, did an Igalia Chats episode about the debate, which I think is a decent exploration of the pros and cons of each approach for anyone interested.
But then, maybe you don’t actually need to explore the two sides of the debate, because there’s a new proposal in town. It’s currently being called Item Flow (which I can’t stop hearing sung by Eddie Vedder, please send help) and is explained in some detail in a blog post from the WebKit team. The short summary is that it takes the flow and packing capabilities from flex and grid and puts them into their own set of properties, along with some new capabilities.
As an example, here’s a thing you can currently do with flexbox:
display: flex;
flex-wrap: wrap;
flex-direction: column;
If the current Item Flow proposals are taken as-is, you could get the same behavior with:
display: flex;
item-wrap: wrap;
item-direction: column;
…or, you could more compactly write it as:
display: flex;
item-flow: wrap column;
Now you might be thinking, okay, this just renames some flex properties to talk about items instead and you also get a shorthand property; big deal. It actually is a big deal, though, because these item-*
properties would apply in grid settingsas well. In other words, you would be able to say:
display: grid;
item-flow: wrap column;
Hold up. Item wrapping… in grid?!? Isn’t that just the same as what grid already does? Which is an excellent question, and not one that’s actually settled.
However, let’s invert the wrapping in grid contexts to consider an example given in the WebKit article linked earlier, which is that you could specify a single row of grid items that equally divide up the row’s width to size themselves, like so:
display: grid;
grid-auto-columns: 1fr;
item-wrap: nowrap;
In that case, a row of five items would size each item to be one-fifth the width of the row, whereas a row of three items would have each item be one-third the row’s width. That’s a new thing, and quite interesting to ponder.
The proposal includes the properties item-pack
and item-slack
, the latter of which makes me grin a little like J.R. “Bob” Dobbs but the former of which I find a lot more interesting. Consider:
display: flex;
item-wrap: wrap;
item-pack: balance;
This would act with flex items much the way
text-wrap: balance
acts with words. If you have six flex items of roughly equal size, they’ll balance between two rows to three-and-three rather than five-and-one. Even if your flex items are of very different sizes, item-pack: balance
would do always automatically its best to get the row lengths as close to equal as possible, whether that’s two rows, three rows, four rows, or however many rows. Or columns! This works just as well either way.
There are still debates to be had and details to be worked out, but this new direction does feel fairly promising to me. It covers all of the current behaviors that flex and grid flowing already permit, plus it solves some longstanding gripes about each layout approach and while also opening some new doors.
The prime example of a new door is the aforementioned masonry layout. In fact, the previous code example is essentially a true masonry layout (because it resembles the way irregular bricks are laid in a wall). If we wanted that same behavior, only vertically like Pinterest does it, we could try:
display: flex;
item-direction: column; /* could also be `flex-direction` */
item-wrap: wrap; /* could also be `flex-wrap` */
item-pack: balance;
That would be harder to manage, though, since for most writing modes on the web, the width is constrained and the height is not. In other words, to make that work with flexbox, we’d have to set an explicit height. We also wouldn’t be able to nail down the number of columns. Furthermore, that would cause the source order to flow down columns and then jump back to the top of the next column. So, instead, maybe we’d be able to say:
display: grid;
grid-template-columns: repeat(3,1fr);
item-direction: row;
item-pack: dense balance;
If I’ve read the WebKit article correctly, that would allow Pinterest-style layout with the items actually going across the columns in terms of source order, but being laid out in packed columns (sometimes called “waterfall” layout, which is to say, “masonry” but rotated 90 degrees).
That said, it’s possible I’m wrong in some of the particulars here, and even if I’m not, the proposal is still very much in flux. Even the property names could change, so values and behaviors are definitely up for debate.
As I pondered that last example, the waterfall/Pinterest layout, I thought: isn’t this visual result essentially what multicolumn layout does? Not in terms of source order, since multicolumn elements run down one column before starting again at the top of the next. But that seems an easy enough thing to recreate like so:
display: grid;
grid-template-columns: repeat(3,1fr);
item-direction: column;
item-pack: dense balance;
That’s a balanced set of three equally wide columns, just like in multicol. I can use gap
for the column gaps, so that’s handled. I wouldn’t be able to set up column rules — at least, not right now, though that may be coming thanks to the Edge team’s gap decorations proposal. But what I would be able to do, that I can’t now, is vary the width of my multiple columns. Thus:
display: grid;
grid-template-columns: 60% 40%; /* or 3fr 2fr, idc */
item-direction: column;
item-pack: dense balance;
Is that useful? I dunno! It’s certainly not a thing we can do in CSS now, though, and if there’s one thing I’ve learned in the past almost three decades, it’s that a lot of great new ideas come out of adding new layout capabilities.
So, if you’ve made it this far, thanks for reading and I strongly encourage you to go read the WebKit team’s post if you haven’t already (it has more detail and a lovely summary matrix near the end) and think about what this could do for you, or what it looks like it might fall short of making possible for you.
As I’ve said, this feels promising to me, as it enables what we thought was a third layout mode (masonry/waterfall) by enriching and extending the layout modes we already have (flex/grid). It also feels like this could eventually lead to a Grand Unified Layout Platform — a GULP, if you will — where we don’t even have to say whether a given layout’s display
is flex
or grid
, but instead specify the exact behaviors we want using various item-*
properties to get just the right ratio of flexible and grid-like qualities for a given situation.
…or, maybe, it’s already there. It almost feels like it is, but I haven’t thought about it in enough detail yet to know if there are things it’s missing, and if so, what those might be. All I can say is, my Web-Sense is tingling, so I’m definitely going to be digging more at this to see what might turn up. I’d love to hear from all y’all in the comments about what you think!
One Comment
Thanks for sharing this piece, always learning great stuff.