Home / Blog / CSS masonry

CSS Masonry in 2026: display: grid-lanes and Browser Support

Published October 2, 2026 · 12 min read · by the CSS DNA team

Quick answer: Native CSS masonry is now called Grid Lanes and is written display: grid-lanes, with lanes defined by grid-template-columns. Safari 26.4 shipped it on macOS and iOS on March 24, 2026. As of October 2, 2026, Chrome and Edge (140+) and Firefox still keep it behind a flag, so roughly one visitor in ten gets it. Ship CSS columns or a small JavaScript placement as the default and upgrade inside @supports (display: grid-lanes).

Masonry is the layout people have asked CSS for since Pinterest made it famous: items of different heights packed into columns, each new item dropping into whichever column is currently shortest. It took nine years of proposals, two competing syntaxes and a public naming survey to settle. The result is settled now, it is in one stable browser, and most of what you will read about its support is out of date in one direction or the other.

The correction: Safari did ship it, and Firefox did not

Two opposite mistakes are circulating. The first says no browser has shipped masonry and that reports of Safari 26.4 support were wrong. They were right. WebKit’s Safari 26.4 feature announcement, published March 24, 2026, says “Safari 26.4 adds support for Grid Lanes” and that “this capability is available in CSS with display: grid-lanes,” including the flow-tolerance property. Can I Use and MDN’s compatibility data both record Safari and Safari on iOS 26.4 as supported, and Safari 27.0 added Grid-Lanes badges to Web Inspector in September.

The second mistake says Firefox 155 and later implement masonry through grid-template-columns: masonry. Firefox has carried an implementation of the older grid-template-*: masonry syntax since Firefox 77 in 2020, but only behind the layout.css.grid-template-masonry-value.enabled preference. Can I Use lists it as disabled by default in every Firefox version through 160, and MDN’s data has display: grid-lanes as unsupported in Firefox. Firefox 155 (September 1, 2026) changed nothing here. Writing grid-template-columns: masonry in production does nothing for Firefox users and nothing for anyone else either.

Browser support as of October 2, 2026

Browserdisplay: grid-lanesNotes
Safari, macOS and iOSShipped in 26.4March 24, 2026, with flow-tolerance. Earlier versions back to 16.4 had masonry behind a feature flag.
ChromeFlag onlyBehind the CSS Grid Lanes Layout flag since 140. No shipping milestone set.
EdgeFlag onlySame Chromium flag. Microsoft engineers lead the Chromium implementation.
FirefoxFlag onlyOlder grid-template-*: masonry syntax behind a preference since 77. Needs updating to grid-lanes.
Samsung Internet, OperaNoWill follow Chromium.

Can I Use puts global support at about 11%, almost all of it Safari. The Chrome Platform Status entry lists dense packing, reverse placement, subgrid and fragmentation among the gaps still open in Chromium’s version. WebKit’s own “when will Grid Lanes arrive” post from January 2026 said the same about the other engines: they are working on it, with no date.

How the syntax got here

If you have code from an older tutorial, this is why it does not work:

  1. 2020: the first draft extends Grid with a masonry keyword, written grid-template-rows: masonry for a column waterfall. Firefox 77 implements it behind a flag. Safari Technology Preview adds the same syntax in 2023.
  2. 2024: the Chrome team proposes a separate layout mode, display: masonry, with its own track properties, arguing that masonry should not overload Grid. WebKit argues the opposite and asks developers to weigh in.
  3. January 31, 2025: the CSS Working Group resolves to reuse Grid’s templating and placement properties, so grid-template-columns, gap and grid-column keep working.
  4. November 2025: after a survey with more than 300 responses, the group resolves that “masonry switch will be display: grid-lanes.”
  5. January 7, 2026: the tolerance property, briefly called item-tolerance, is renamed flow-tolerance.
  6. March 24, 2026: Safari 26.4 ships the finished core syntax.

So grid-template-rows: masonry and display: masonry are both dead syntaxes. Neither will ever ship in a stable browser. The specification now lives in CSS Grid Layout Level 3.

The grid-lanes syntax

.gallery {
  display: grid-lanes;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}

That is a complete Pinterest layout. Items keep their natural height and each one goes into the lane that is currently shortest. You define lanes along one axis only:

  • Set grid-template-columns and you get vertical lanes, the waterfall. This is the default: the spec says that unless columns are none and rows are set, the inline axis is the grid axis.
  • Set only grid-template-rows and you get horizontal lanes, the brick wall that photo sites use for rows of mixed-width images.
  • grid-column: span 2 works, so a featured item can cover two lanes. You can also pin an item to a lane with grid-column: 1.
  • flow-tolerance (initial value normal, which resolves to 1em) treats lanes within that distance of each other as tied, so an item goes to the earlier lane instead of jumping across the page for a two-pixel advantage. Raise it to keep the order more row-like. infinite is also valid.

Live demo: native, JavaScript or columns

Which masonry path is your browser on?

The demo picks native Grid Lanes when CSS.supports('display', 'grid-lanes') is true and the JavaScript fallback otherwise. Switch paths and watch the numbers: they are the DOM order.

Checking your browser…

Layout path

Applied CSS

Compare the JS fallback with CSS columns. Both look like masonry, but in columns item 2 sits under item 1 rather than beside it, because multi-column layout fills each column top to bottom before moving right. Grid Lanes and the JS placement both go across, which is what a reader scanning a feed expects.

What to ship today

With nine in ten visitors on a browser without Grid Lanes, the fallback is the real layout for most people. Pick it on purpose.

ApproachVisual orderGapsJavaScriptGood for
CSS columnsDown each columnNoneNoneUnordered galleries, quotes, testimonials
Grid with dense and spansMostly across, reordered to fill holesSome, unless every height is a multiple of the rowNoneCards with a few known size classes
Grid plus JS placementAcross, true masonryNone~25 lines, reruns on resizeFeeds and anything where order matters
Masonry libraryAcrossNoneA dependency, absolute positioningLegacy code you are not touching yet

CSS columns

.gallery {
  columns: 220px;        /* as many 220px+ columns as fit */
  column-gap: 16px;
}
.gallery > * {
  break-inside: avoid;   /* keep each card in one piece */
  margin-bottom: 16px;
}

Zero JavaScript and works everywhere. The cost is order: item 2 is below item 1, and adding items later reshuffles every column. Fine for a photo gallery, wrong for a chronological feed.

Grid with dense packing

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  grid-auto-rows: 120px;
  grid-auto-flow: dense;
  gap: 16px;
}
.tall { grid-row: span 2; }
.wide { grid-column: span 2; }

This is the “bento” look rather than masonry. Items snap to row multiples, and dense backfills holes by pulling later items forward, which breaks the match between visual and DOM order. It works when you control the content and can assign a size class to each card. For the trade-offs between the two layout modes in general, see Flexbox vs Grid.

A small JavaScript fallback

This is the code the demo runs. It keeps the element a normal grid, sets 1px rows, and places each item explicitly in the shortest column. The container’s height stays automatic, so nothing is absolutely positioned and the page flows normally around it.

function placeLanes(grid) {
  const cs = getComputedStyle(grid);
  const lanes = cs.gridTemplateColumns.split(' ').length;
  const gap = parseFloat(cs.columnGap) || 0;
  const filled = new Array(lanes).fill(0);

  for (const item of grid.children) {
    item.style.gridRow = item.style.gridColumn = '';
    item.style.alignSelf = 'start';
    const h = Math.ceil(item.getBoundingClientRect().height);
    let lane = 0;
    for (let i = 1; i < lanes; i++) {
      if (filled[i] < filled[lane] - 16) lane = i; // 16px ≈ flow-tolerance: 1em
    }
    item.style.gridColumn = lane + 1;
    item.style.gridRow = (filled[lane] + 1) + ' / span ' + h;
    filled[lane] += h + gap;
  }
}

/* .gallery { display: grid; grid-auto-rows: 1px; row-gap: 0; ... } */
if (!CSS.supports('display', 'grid-lanes')) {
  const grid = document.querySelector('.gallery');
  let lastWidth = 0;
  new ResizeObserver(([entry]) => {
    if (entry.contentRect.width !== lastWidth) {
      lastWidth = entry.contentRect.width;
      placeLanes(grid);
    }
  }).observe(grid);
}

Two details matter. Rerun it when images load, or give every <img> its width and height attributes so the height is known before the file arrives. And only rerun on width changes, because placement changes the grid’s height and a naive observer will loop.

Progressive enhancement with @supports

Write the fallback as the default and put Grid Lanes inside a feature query. Browsers without support skip the block entirely:

.gallery {
  columns: 220px;
  column-gap: 16px;
}
.gallery > * { break-inside: avoid; margin-bottom: 16px; }

@supports (display: grid-lanes) {
  .gallery {
    display: grid-lanes;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
    columns: auto;            /* undo the fallback */
  }
  .gallery > * { margin-bottom: 0; }
}

If your fallback is a plain grid, the shortest version relies on the cascade dropping values it does not understand:

.gallery {
  display: grid;            /* everyone */
  display: grid-lanes;      /* overrides it where supported */
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}

Keep the JavaScript behind CSS.supports('display', 'grid-lanes') as in the snippet above, so Safari users never download or run it. Someone who turns on the Chrome flag will also pass the check and get the native path, which is what you want.

Found a masonry layout you want to study? Working out whether a site uses columns, a library or grid-lanes means clicking through nested wrappers in DevTools. CSS DNA, a browser extension for inspecting CSS, copies any element’s CSS in one click, free, so you can read the container’s display and track definitions straight away. Add CSS DNA to Chrome (free).

Order, focus and accessibility

Every masonry approach moves items away from where the DOM puts them. Keyboard focus and screen readers follow the DOM, so in a waterfall a Tab press can jump from the bottom of one column to the top of the next. The Grid Level 3 spec addresses this directly and asks authors to “design layouts where such backtracking is minimized so that focus and reading order can be more easily followed.” In practice:

  • Keep heights within a reasonable range. One very tall item causes most of the backtracking.
  • Raise flow-tolerance when order matters. A larger value keeps items in row order more often, at the cost of slightly less even column heights.
  • Prefer columns-based fallbacks only where order genuinely does not matter, since they are the most out of step with reading order.

How to check and debug

  1. Which path is live? Run CSS.supports('display', 'grid-lanes') in the console. In Safari 26.4+ it returns true. Everywhere else, unless a flag is on, it returns false.
  2. Inspect in Safari. Web Inspector’s Grid overlay supports Grid Lanes as of 26.4, with numbered overlays showing placement order, and Safari 27 adds a Grid-Lanes badge in the Elements tab.
  3. Everything is in one column. grid-template-columns is missing or resolves to a single track. Without a column template there is nothing to divide the container into lanes.
  4. Old syntax in your CSS. Search for masonry. grid-template-rows: masonry is not supported by any stable browser, so the declaration is dropped and you get an ordinary grid with gaps under the short items.
  5. The JS fallback leaves gaps. Heights were measured before images loaded. Add dimensions to images or rerun placement on each image’s load event.
  6. Testing in Chrome. Turn on the flag at about://flags (search “CSS Grid Lanes Layout”). Chromium’s implementation is still incomplete, so test real behaviour in Safari.

Grid Lanes sits next to the other new layout and paint features we track in Modern CSS in 2026. Its mirror image this year is CSS corner-shape, which shipped in Chromium first and is still waiting on Safari.

Frequently asked questions

Can I make a masonry layout with only CSS?

Yes, in two ways. display: grid-lanes gives true masonry in Safari 26.4 and later. Everywhere else, CSS multi-column layout (columns: 220px with break-inside: avoid) produces the same look without JavaScript, but items flow down each column instead of across, so it suits galleries where order does not matter.

Which browsers support CSS masonry?

As of October 2, 2026, only Safari 26.4 and later, on macOS and iOS, supports display: grid-lanes without a flag. It shipped March 24, 2026. Chrome and Edge 140+ have it behind the CSS Grid Lanes Layout flag, and Firefox has an older grid-template-*: masonry implementation behind a preference. Can I Use puts global support near 11%.

Does grid-template-rows: masonry still work?

No. It was the original 2020 syntax and only ever worked behind flags, in Firefox and earlier Safari Technology Preview builds. The CSS Working Group replaced it with display: grid-lanes in November 2025, and Safari 26.4 ships only the new syntax. Search your stylesheets for masonry and replace it.

What happened to display: masonry?

It was Chrome’s 2024 proposal for a separate masonry layout mode. The working group chose to build on Grid’s properties instead, and in November 2025 picked the name grid-lanes after a public survey. Chromium’s flagged implementation is being updated to the final syntax, so display: masonry will not ship.

What is flow-tolerance?

flow-tolerance sets how much shorter a lane must be before an item skips ahead to it. The initial value normal resolves to 1em; lanes within that distance count as tied and the earlier lane wins. Larger values keep items closer to reading order. It was called item-tolerance until a January 7, 2026 rename.

Read any site’s layout in one click

Copy an element’s CSS, sample colors, and see a site’s palette and fonts as a design-system preview. It runs on-device.

Add CSS DNA to Chrome (free)

Free: element CSS, eyedropper, ranked palette. Pro, $5/mo after a 7-day trial: exports, DESIGN.md, CSS audit. No account.