![Rachel Andrew](https://web.dev/images/authors/rachelandrew.jpg) Rachel Andrew Technical Writer [GitHub](https://github.com/rachelandrew) [LinkedIn](https://www.linkedin.com/in/rachelandrew) [Mastodon](https://front-end.social/@rachelandrew) [Bluesky](https://bsky.app/profile/rachelandrew.bsky.social) [Homepage](https://rachelandrew.co.uk) ![Ian Kilpatrick](https://web.dev/images/authors/iankilpatrick.jpg) Ian Kilpatrick [GitHub](https://github.com/bfgeek) ![Tab Atkins-Bittner](https://web.dev/images/authors/tabatkins.jpg) Tab Atkins-Bittner

<br />


Published: September 19, 2024, Last updated: February 13, 2026

<br />

> [!WARNING]
> **Warning:** Outdated Syntax: The code samples in this post are based on an early draft of what is now known as "Grid lanes layout". Refer to [the css-grid-3 specification](https://www.w3.org/TR/css-grid-3/) for the latest version of the syntax.

The CSS Working Group has combined the two CSS masonry proposals into
[one draft specification](https://drafts.csswg.org/css-grid-3/).
The group hopes that this
will make it easier to compare the two, and make a final decision. The Chrome
team still believes that a separate masonry syntax would be the best way
to proceed. While the biggest performance issue mentioned in [our previous
post](https://developer.chrome.com/blog/masonry) is resolved, there are still concerns around syntax,
initial values, and how easy a version combined with grid would be to learn.

To test our assumptions however, we've worked through some examples to show how
masonry would work with each version. Take a look at the examples in this post
and give us your feedback, so we can make a decision and proceed with this
feature.

This post doesn't cover all possible use cases, however it's clear that
separating masonry from grid layout won't result in the feature lacking
functionality. In fact, the opposite may be true. As you'll see in this post,
the `display: masonry` version creates new opportunities and a simpler syntax.
In addition, many developers have raised concerns about the potential of
re-ordering items with masonry causing accessibility issues. This is also being
addressed for both versions of the syntax, through the proposed `reading-flow`
property.

## A basic masonry layout

This is the layout most people imagine when thinking about masonry. Items
display in rows, and after the first row is placed, subsequent items move into
space left by shorter items.
![A layout with columns, the items filling columns do so with no gaps.](https://developer.chrome.com/static/blog/masonry-syntax/image/image1.png) In this layout columns are defined, then items are filled in by masonry rather than strict rows.

### With `display: masonry`

To create a masonry layout use the value of `masonry` for the `display`
property. This creates a masonry layout with column tracks that you define (or
are defined by the content) and masonry in the other axis. The first item is
displayed at block and inline start (therefore top left in English), and items
are laid out in the inline direction.

To define tracks use `masonry-template-tracks` with track listing values as used
in CSS grid layout.

    .masonry {
      display: masonry;
      masonry-template-tracks: repeat(3, 1fr);
      gap: 10px;
    }

### With `display: grid`

To create a masonry layout, first create a grid layout using the value of `grid`
for the `display` property. Define columns with the `grid-template-columns`
property, then give `grid-template-rows` a value of `masonry`.

This will create a layout as you'd expect with auto-placed grid items, however
the items in each row use a masonry layout and will rearrange to take up space
left by smaller items in the preceding row.

    .masonry {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      grid-template-rows: masonry;
      gap: 10px;
    }

### Points to consider between the two options

A notable difference between these methods is that with the `display: masonry`
version, you get a masonry layout even if you don't specify any tracks with
`masonry-template-tracks`. Therefore `display: masonry` might be all you need.
This is because the initial value of `masonry-template-tracks` is
`repeat(auto-areas, auto)`. The layout creates as many auto-sized tracks as will
fit the container.

## Reversed flow with masonry

The specification includes ways to change the direction of the masonry flow. For
example, you can change the flow to display from the block-end up.
![A layout with columns, the items filling columns do so from the bottom of the layout.](https://developer.chrome.com/static/blog/masonry-syntax/image/image3.png) In this layout columns are defined, then items are filled in by masonry starting at the block end.

### With `display: masonry`

Create a masonry layout with `display: masonry`, then use `masonry-direction`
with a value of `column-reverse`.

    .masonry {
      display: masonry;
      masonry-template-tracks: repeat(3, 1fr);
      masonry-direction: column-reverse;
    }

### With `display: grid`

Create a masonry layout with `display: grid` and `grid-template-rows: masonry`.
Then use the `grid-auto-flow` property with a new value of `row-reverse` to
cause the items to layout from the block end of the grid container.

    .masonry {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      grid-template-rows: masonry;
      grid-auto-flow: row-reverse;
    }

### Points to consider between the two options

The `display: masonry` version feels very similar to how flexbox works. Change
the direction that columns flow using the `masonry-direction` property with a
value of `column-reverse`.

The CSS grid version uses `grid-auto-flow`. As currently defined
`grid-auto-flow: row-reverse` and `grid-auto-flow: column-reverse` would give
the same effect. This could be confusing, as you might expect them to do
something different.

## Masonry for rows

You could also change direction to define rows.
![A layout with rows, the items filling rows do so with no gaps.](https://developer.chrome.com/static/blog/masonry-syntax/image/image2.png) In this layout rows are defined, then items are filled in by masonry rather than strict columns.

### With `display: masonry`

Create a masonry layout with `display: masonry`, then set the value of
`masonry-direction` to `row`. Unless you want your rows to have a specific block
size, you don't need to specify any track sizing as the default is `auto`,
therefore the tracks will size to the content they contain.

    .masonry {
      display: masonry;
      masonry-direction: row;
    }

### With `display: grid`

    .masonry {
      display: grid;
      grid-template-columns: masonry;
      grid-template-rows: repeat(3, 1fr);
    }

### Points to consider between the two options

As with reversed flow, changing the `display: masonry` version from columns to
rows, means changing the value of `masonry-direction`. With the grid version,
you will need to switch the values of the `grid-template-columns` and
`grid-template-rows` properties. Or, if using the shorthand, change the order of
the syntax.

With both of these examples of switching flow, the `display: masonry` version
feels more intuitive. There's a single property controlling flow
`masonry-direction`, it takes one of the following values:

- `row`
- `column`
- `row-reverse`
- `column-reverse`

You then add any sizing information needed to `masonry-template-tracks`,
assuming the default auto value is not what you need.

With grid, to do the reverse direction you need to use the `grid-auto-flow`
property, and to do the row masonry switch the value of the `grid-template-*`
properties. It's also not possible in current grid syntax to leave the value for
the grid axis undefined. You always need to specify `grid-template-*` properties
on the axis that doesn't have a value of `masonry`.

## Position items

In both versions you can explicitly position items using the line-based
placement you will be familiar with from grid layout. In both versions you can
only position items in the *grid axis*, this is the axis with the predefined
tracks, you can't position items on the axis that is doing the masonry layout.

### With `display: masonry`

The following CSS defines a masonry layout with four columns. The grid axis is
therefore columns. The item with a class of `a` is placed from the first column
line to the third column line, spanning two tracks with the new
`masonry-track-*` properties. This can also be defined as a shorthand of
`masonry-track: 1 / 3;`.

    .masonry {
      display: masonry;
      masonry-template-tracks: repeat(4, 1fr);
    }

    .a {
      masonry-track-start: 1;
      masonry-track-end: 3;
    }

### With `display: grid`

The following CSS defines a masonry layout with four columns. The grid axis is
therefore columns. The item with a class of `a` is placed from the first column
line to the third column line, spanning two tracks with the `grid-column-*`
properties. This can also be defined as a shorthand of `grid-column: 1 / 3;`.

If the grid axis is columns then the `grid-row-*` properties will be ignored,
and if the grid axis is rows, the `grid-columns-*` properties will be ignored.

    .masonry {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      grid-template-rows: masonry;
    }

    .a {
      grid-column-start: 1;
      grid-column-end: 3;
    }

You can use named lines with both syntaxes. The following examples show a grid
with two column lines named `a`.

### With `display: masonry`

The named lines are defined in the track listing value of
`masonry-template-tracks`. The item can be placed after any line named `a`.

    .masonry {
      display: masonry;
      masonry-template-tracks: 100px [a] auto [a] auto 100px;
    }

    .item {
      masonry-track: a;
    }

### With `display: grid`

The named lines are defined in the track listing value of
`grid-template-columns`. The item is placed after the first line named `a`. If
the `grid-row` property is defined it will be ignored.

    .masonry {
      display: grid;
      grid-template-columns: 100px [a] auto [a] auto 100px;
      grid-template-rows: masonry;
    }

    .item {
      grid-column: a;
      grid-row: a; /* ignored */
    }

You can also use named areas in both syntaxes. The following examples show a
grid with three tracks named "a", "b", and "c".

### With `display: masonry`

The tracks are named as the value of `masonry-template-areas`. Because no track
sizes are defined, all three default to `auto` size. The item is placed in the
"a" track.

    .masonry {
      display: masonry;
      masonry-template-areas: "a b c";
    }

    .item {
      masonry-track: a;
    }

This works the same whether you are defining rows or columns; the only
difference would be the `masonry-direction` property.

### With `display: grid`

For *columns* , the syntax is essentially identical. Similarly, because no track
sizes are defined, all three default to `auto` size, but you do still need to
explicitly say that the other axis is masonry:

    .masonry {
      display: grid;
      grid-template-areas: "a b c";
      grid-template-rows: masonry;
    }

    .item {
      grid-column: a;
    }

For *rows* , however, the value has to be written differently, because
`grid-template-areas` is actually defining a two-dimensional area, and each row
is written as a separate string:

    .masonry {
      display: grid;
      grid-template-areas: "a" "b" "c"; /* Note the difference, each row is quoted. */
      grid-template-columns: masonry;
    }

    .item {
      grid-row: a;
    }

### Points to consider between the two options

With any positioning, the `display: masonry` syntax works better when it comes
to switching direction. As the `masonry-track-*` property works in whichever
direction is the grid axis, all you need to do to change direction is change the
value of `masonry-direction`. With the grid version, at the least you'll need
redundant properties to enable the switching. However, see the previous examples
for other ways in which changing direction is more complicated with the grid
version.

## Shorthands

In this post the longhands have been used to make it clearer which properties
are in use, however both the `display: masonry` and `display: grid` versions can
be defined using shorthands.

### With `display: masonry`

The `display: masonry` shorthand uses the `masonry` keyword. To create the basic
masonry layout use the following CSS:

    .masonry {
      display: masonry;
      masonry: repeat(3, 1fr);
    }

To create a simple row-based masonry layout:

    .masonry {
      display: masonry;
      masonry: row;
    }

To define tracks and a row-based layout with the shorthand:

    .masonry {
      display: masonry;
      masonry: repeat(3, 1fr) row;
    }

### With `display: grid`

To create the basic masonry layout using the `grid` shorthand.

    .masonry {
      display: grid;
      grid: masonry / repeat(3, 1fr);
    }

To create a simple row-based masonry layout:

    .masonry {
      display: grid;
      grid: repeat(3, auto) / masonry;
    }

> [!NOTE]
> **Note:** In the grid version you always have to define tracks on the non-masonry axis. This is a key difference between the two versions.

In more complex examples, because the overall `display:masonry` syntax is
simpler, more properties can be packed together into the shorthand without it
becoming overly complex.

For example, imagine creating three columns, named "a", "b", and "c", filled
from the bottom up.

### With `display:masonry`

In `display: masonry`, all three of these can be set together in the shorthand:

    .masonry {
      display: masonry;
      masonry: column-reverse "a b c";
    }

Because they're auto-sized, you don't need to specify the sizes, but if you
wanted a specific size instead, that could be added. For example:
`masonry: column-reverse 50px 100px 200px "a b c";`.

Also, each component can be freely reordered; there is no specific order you
need to remember. And if you wanted to do rows instead, all you need to do is
swap `column-reverse` with `row` or `row-reverse`; the rest of the syntax stays
the same.

### With `display: grid`

In `display: grid`, these three aspects have to be set separately:

    .masonry {
      display: grid;
      grid-template-rows: masonry;
      grid-template-areas: "a b c";
      grid-auto-flow: wrap-reverse;
    }

Like the masonry example, this makes all the columns `auto` size, but if you
wanted to supply explicit sizes, you can do so:

    .masonry {
      display: grid;
      grid: masonry / 50px 100px 200px;
      grid-template-areas: "a b c";
      grid-auto-flow: wrap-reverse;
    }

Or if you wanted to use 'grid' to set sizes and area names all together:

    .masonry {
      display: grid;
      grid: "a b c" masonry / 50px 100px 200px;
      grid-auto-flow: wrap-reverse;
    }

In both of these examples, the order is strictly required, and different if you
wanted rows instead. For example, changing to rows looks like:

    .masonry {
      display: grid;
      grid: 50px 100px 200px / masonry;
      grid-template-areas: "a" "b" "c";
    }

Or, to put them all into one shorthand:

    .masonry {
      display: grid;
      grid: "a" 50px "b" 100px "c"  200px / masonry;
    }

### Points to consider between the two options

The `display: masonry` shorthand is likely to be widely used, given that it's a
relatively straightforward shorthand. In many cases, for a "standard" masonry
layout, you'll just set the track definitions; all other values can assume the
default.

The `display: grid` version uses the existing
[`grid`](https://developer.mozilla.org/docs/Web/CSS/grid) shorthand, which is a
fairly complex shorthand, and is in our experience less frequently used by
developers. As shown in the preceding examples, even when used for simple
masonry layouts it requires care when setting the order of values.

## Other considerations

This post looks at some common use cases today, however we don't know what the
future might hold for grid or masonry. A big argument for using the separate
`display: masonry` syntax is it allows the two to diverge in future. In
particular with initial values---such as those for `masonry-template-tracks`---it
might be useful to do something different in masonry than grid does. We can't
change the grid defaults if we go with the `display: grid` version, this could
limit things we might want to do in the future.

In these examples, you can see places where the browser has to ignore
properties that are valid in grid if using masonry.
For example `grid-template-areas`, where most of the values get
through away as it defines a two dimensional grid layout, in masonry we are only
fully defining one direction.

## Provide your feedback

Take a look at these examples, and also the draft specification which lays each
version out alongside the other. Let us know what you think by commenting on
[Issue 9041](https://github.com/w3c/csswg-drafts/issues/9041) or, if you prefer
to write a post on your own blog or on social media, be sure to let us know on
[X](https://x.com/ChromiumDev) or
[LinkedIn](https://www.linkedin.com/showcase/chrome-for-developers).