Should masonry be part of CSS grid?
Currently, the CSS Working Group (CSSWG) is discussing whether to include masonry as part of CSS grid, or as a new layout module?
In this article, I will share my thoughts and examples about whether it should be part of the CSS grid or not.
What is masonry layout?
First of all, a few details in case you are not aware of what masonry is.
A layout type is also called the “waterfall”, where elements with different widths or height stack horizontally or vertically.
Here is an example of vertically stacked elements. This has been known as the “Pinterest” layout for years.
In this article, I will go through examples that don’t look like the Pinterest layout. In particular, examples that might use CSS masonry on demand.
The debate on the syntax
Currently, there is a debate on whether to make masonry part of the CSS grid, or as a separate layout module. You can look at the following blog posts for more info.
Feedback needed: How should we define CSS masonry? - Chrome blog
Help us choose the final syntax for Masonry in CSS - Webkit blog
The Name
I agree with this webkit article about the name.
In CSS, the names and keywords are simple and easy to read and write. Some options work better in my opinion. For example:
waterfall
packed
collapse (as suggested by the Webkit blog)
brick
.masonry {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-rows: collapse;
gap: 1rem;
}
To me, packed
or collapse
work better.
Imagine if display: flexbox
were named display: rubberband
, or if CSS display: grid
is named display: chessboard
. That feels the same to me when I read display: masonry
.
My Thoughts on debate
if the new syntax is supported now , how we should use it?
If we go with the new syntax (display: masonry
), it will need a few years to become supported in all major browsers. Let’s be honest, a layout is a major part of a web page that makes it hard to apply progressive enhancement. You either have a masonry or not, right?
Making it part of CSS grid will at least guarantee that the layout will work, but without the masonry stuff.
Responsive Design
In practical CSS applications, it’s rare to find a grid like this:
.masonry {
display: masonry;
masonry-template-tracks: repeat(3, 1fr);
masonry-direction: column-reverse;
}
It might be like this:
.masonry {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
padding: 1rem;
@media (min-width: 700px) {
display: masonry;
masonry-template-tracks: repeat(3, 1fr);
gap: 10px;
padding: 0;
&:has(.card-fixed) {
display: grid;
}
}
}
At the end of the day, masonry is a grid. If we go with the new syntax, then changing a layout will require changing the whole layout module (grid, masonry, or flex). This is too much work.
Masonry is a grid
Masonry is a grid, right? Introducing a new layout module would require a significant learning curve to fully understand and memorize new properties.
Fun fact: I still can’t memorize some grid properties or values, let alone get a new layout module for masonry.
Consider the following example. We have a typical grid where all the grid items have the same size.
.layout {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
}
If some of the grid items have a larger height than the others, the layout will look like this if we’re using CSS grid. Try to toggle between “Same size” and “Dynamic size”.
At this point, it doesn’t make sense to have a new layout module (i.e.: display: masonry
) only because a few items have a larger height (At least for me).
In a real-life case, I might need:
have a normal grid on small viewport sizes, then switch to masonry on larger ones.
or apply masonry if there are 10+ items in the grid
or apply masonry if items have the class
dynamic-size
and so on.. the options are endless
A masonry layout doesn’t necessarily imply that a layout is always masonry. It can be a mix of flexbox, normal grid, and masonry grid. It might be needed to be applied to an already defined grid.
Try to switch between the options below. Note: the masonry option works in Firefox and Safari Technology Preview at the time of writing this article.
Example of the new vs the grid-integrated syntax
We have a footer layout where sections are displayed next to each other. Here is the design:
When there is no enough space, the footer groups will wrap. This is a default behaviour in CSS grid.
How would you build this layout? Let’s assume that we’ll use a CSS grid.
.footer {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 1rem;
}
With that, the grid works fine. Try to resize it.
Let’s explore enhancing this layout by using masonry.
Grid-integrated option
In this solution, the grid is enhanced by adding masonry
as a value for grid-template-rows
.
.footer {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
grid-template-rows: masonry;
gap: 1rem;
}
In the following demo, try:
Resizing the layout.
Toggle the checkbox to see the difference between the default grid and masonry.
Grid-independent option
If the grid-independent option is used, how will it work? I have a few thoughts:
This is a grid by default and I don’t know the exact number of items it will have.
Even if I know the number of footer groups, they will need to be arranged differently when the viewport/container width is resized.
If I need to change to a new layout module, how I can manage them in the default grid style (i.e: no)
Let’s explore using the grid-independent option. Please note that the following CSS still doesn’t work in any browser.
.footer {
display: masonry;
masonry-template-tracks: repeat(auto-fit, minmax(120px, 1fr));
gap: 1rem;
}
As a developer, if I want masonry
to be applied to a grid under certain cases, I will be forced to use display:masonry
. For me, that doesn’t make sense because:
It will fail in browsers that don’t support
display: masonry
. I can write fallback, but why write more CSS when we can avoid it upfront by integrating it into the CSS grid?It’s a duplication of the CSS grid syntax.
News Layout
In this example, we have a news section. It contains a featured news item on a large viewport and a grid with 3 columns.
Try to resize the layout and see how it behaves.
Here is the default grid CSS:
.layout {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1rem;
}
.card.featured {
@container news (min-width: 600px) {
grid-column: 1 / -1;
display: grid;
grid-template-columns: max-content 1fr;
}
}
If we want to enable masonry, we’ve two options.
Grid-integrated option
.layout {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
grid-template-rows: masonry;
gap: 1rem;
}
.card.featured {
@container news (min-width: 600px) {
grid-column: 1 / -1;
display: grid;
grid-template-columns: max-content 1fr;
}
}
Grid-independent option
Take a look:
.layout {
display: masonry;
masonry-template-tracks: repeat(auto-fit, minmax(180px, 1fr));
gap: 1rem;
}
For the featured card, I want to place it from the start to the end column with 1 / -1
. According to the css-grid-3 spec:
Item placement in the grid axis of a masonry container is established with the masonry-track-start and masonry-track-end properties (and their masonry-track shorthand), whose syntax and interpretation are analogous to the grid-column-start and grid-column-end properties (and their grid-column shorthand).
That means I need to replace grid-column
with masonry-track
.
.card.featured {
@container news (min-width: 600px) {
masonry-track: 1 / -1;
display: grid;
grid-template-columns: max-content 1fr;
}
}
Let’s assume that I want to use display: masonry
as an enhancement.
.layout {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1rem;
}
.card.featured {
@container news (min-width: 600px) {
grid-column: 1 / -1;
display: grid;
grid-template-columns: max-content 1fr;
}
}
@supports (display: masonry) {
.layout {
display: masonry;
masonry-template-tracks: repeat(auto-fit, minmax(180px, 1fr));
/*gap: 1rem;*/ /* gap is already there */
}
.card-featured {
@container news (min-width: 600px) {
/* Do we need to reset grid-column,
or masonry-track will override it? */
grid-column: initial;
masonry-track: 1 / -1;
}
}
}
If we compare the above to the grid-integrated option, the most obvious difference is that grid-template-rows: masonry
will work on supported browsers. If not, it will simply show the default behavior.
Another example that shows how masonry can be useful on top of CSS grid, not a separate layout module.
Section Layout
In this design, we have a section that consists of:
Headline and description
Gallery of images
Headline and description
Gallery of images
We need to build the image gallery dynamically:
On small sizes, the images will get a masonry style, but when the image container is wider (around tablet size), the images should be squared
If there are 5+ photos, the layout will change (e.g: square look).
See the following figure: