CSS Grid Lanes: Native Masonry in Safari
Masonry layout, the staggered Pinterest-style grid where items of any size flow into the space available, has shipped in production for over a decade on the back of JavaScript libraries, floats, and Flexbox hacks that almost work until they don’t.1 At WWDC 2026, Apple’s Safari team gave the web a native layout mode for it: CSS Grid Lanes. The masonry pattern is old. A first-class CSS display type that produces it in three lines, plus a flow-tolerance dial that fixes masonry’s chronic tab-order and accessibility problem, is new. Grid Lanes is available today in Safari 26.4 and behind a flag in other browsers.1
TL;DR
- Grid Lanes is a new CSS layout mode that sits between Grid and Flexbox: it structures one axis and leaves the other free, distributing content across multiple lanes into a tightly packed, staggered layout that preserves each item’s natural proportions.1
- The whole thing is three lines:
display: grid-lanes,grid-template-columnswithfrtracks, andgap. Swapgrid-template-columnsforgrid-template-rowsto flip a waterfall into a brick wall. You pick one direction, not both.1 - Track sizing carries over from Grid: unequal
frratios,auto-fillwithminmax()for responsive column counts, and repeating narrow/wide patterns.1 - Items use Grid properties you already know:
grid-column: span 2to widen, explicit column placement, andgrid-template-columns: subgridto fold a card’s contents into the parent layout. You control column placement, not row; Grid Lanes decides the row.1 flow-toleranceis the sharp differentiator. Pure shortest-column placement can make tab order zigzag against the visual order, hurting accessibility.flow-tolerance(default1em) loosens the shortest-column rule so placement tracks reading order more closely.1- Availability is honest: Safari 26.4 ships it today, other browsers gate it behind a flag. Grid Lanes is not yet cross-browser GA.1
Where Grid Lanes sits between Grid and Flexbox
Brandon from the Safari team builds a Grid Lanes layout from scratch, starting at 3:39.
Every layout mode answers the same two questions: where do items go, and how much space do they get.1 Flexbox and Grid answer them differently, and Grid Lanes lands in between.
Flexbox gives you one axis and a single lane of items flowing along it; when items wrap, they keep flowing in the chosen direction, row or column.1 Grid gives you two axes, columns and rows, and places items into cells at the intersection of those tracks. The problem shows up when items have different aspect ratios: you get large empty areas where shorter items fail to fill their cells.1 For images, that leaves three poor options. Stretch each image to fill its cell and you distort it; zoom in to fill the space and the image overflows its container; crop it and you risk losing important information.1
Grid Lanes resolves the tension. As the session frames it, “It sits between Grid and Flex. Instead of structuring across two dimensions like Grid, it structures just one, and leaves the other free. But unlike Flex, where content flows in a single lane and wraps down the page, Grid Lanes distributes content across multiple lanes.”1 Items get placed one by one, and each lands in whichever column leaves it closest to the top, which is why earlier items sit higher and later items fill in below.1 The layout works with any content, not only images: text blocks wrap to fit their column and the browser sizes the heights, and a headline can span across columns to stand out.1
Native masonry in three lines of CSS
The build starts with a new display type, then defines tracks the same way Grid does:
.gallery {
display: grid-lanes;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
}
grid-template-columns sets the number of tracks and how wide each becomes. The fr unit (“fractional unit”) tells the browser to take the available space in the container and divide it into fractions, so 1fr 1fr 1fr produces three equally sized columns, and gap adds spacing exactly as it does in Grid.1 To flip the waterfall into a brick wall, swap the columns for rows: replace grid-template-columns with grid-template-rows and the items flow across in rows instead of down in columns. The only catch, in the session’s words: “you pick one direction - not both.”1
Those three lines give more control than they look. Columns don’t have to be equal: a center column can take twice the space of its neighbors. Instead of fixing the column count yourself, you can let the browser decide, the same way responsive Grid layouts already do:
.gallery {
display: grid-lanes;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 10px;
}
auto-fill creates as many columns as will fit, and minmax() says each one should be at least 200 pixels but can grow to fill the space.1 You can take the same idea further with a repeating pattern of narrow and wide columns. The payoff Brandon calls out: “what I love most is how much you can do with just a few lines of CSS.”1
Shaping individual items with Grid properties you know
Grid Lanes shapes items with properties that already exist in Grid. Start from a grid-lanes container with three equal columns. To give one item more space, grid-column: span 2 stretches it across two columns and the rest of the layout adjusts around it.1 You can also place an item exactly: set it to start in column 2 and span columns 2 and 3. The constraint is deliberate: “you can control column placement, but not row. Grid Lanes decides the row for you.”1
subgrid folds a nested component’s contents into the parent. A recipe card that spans two columns holds an image and some text that, by default, don’t participate in the Grid Lanes layout. Add display: grid-lanes and grid-template-columns: subgrid to the card, and “its contents join the parent layout as their own items”: the image takes one column, the text takes the other, each sized to its content.1 Nesting goes either direction, a regular grid inside a Grid Lanes container or the reverse, because the same tools and syntax carry over.1
The flow-tolerance dial: the accessibility fix
Here is the part that makes Grid Lanes more than a tidier masonry. Pure shortest-column placement looks great most of the time, but sometimes it doesn’t quite feel right, and the reason is accessibility.1
Picture two items in a row at nearly the same height, where item 2 is a few pixels shorter than item 1. The area under item 2 sits closer to the top, so the browser places the next item there, and item 4 fills the first column. The visual result reads left-to-right on the first row and right-to-left on the last. As the session puts it: “The difference between tab order and how the content appears visually will impact accessibility for people and can create a confusing experience.”1 Tab order follows source order; the zigzag visual placement breaks the correspondence keyboard and screen-reader users rely on.
flow-tolerance is the dial that loosens or tightens the shortest-column rule.1 With it on, the browser asks for each new item: “is the taller column less than the shorter column plus flow-tolerance?”1 If the gap is within tolerance, the item fills the column that keeps placement aligned with reading order; once the gap grows too big to ignore, the item drops into the genuinely shorter column. The default value is 1em:
.gallery {
display: grid-lanes;
grid-template-columns: 1fr 1fr;
flow-tolerance: 1em;
}
Apple’s guidance is to “try different flow-tolerance values to find what works for your content.”1 The flip side of giving the browser flexibility is that the result can occasionally surprise you, and when it does, Web Inspector has full support for Grid Lanes: turn on the overlay and you get lines for columns and rows, order numbers projected over each item so you can see exactly how placement happened, and the gaps drawn between items.1
Key Takeaways
For frontend developers:
- Replace JavaScript masonry libraries and Flexbox hacks with display: grid-lanes, three fr tracks, and gap; reuse the Grid track-sizing tools (auto-fill, minmax(), unequal fr) you already know.1
- Reach for grid-column: span N and explicit column placement to feature items, and grid-template-columns: subgrid to fold nested card contents into the parent layout.1
For accessibility-minded teams:
- Tune flow-tolerance (default 1em) so visual placement tracks source and tab order, closing the gap that zigzag masonry placement opens for keyboard and screen-reader users.1
- Verify placement with Web Inspector’s Grid Lanes overlay, which projects item order numbers directly over the layout.1
For technical leads planning rollout: - Treat Grid Lanes as Safari-26.4-available, flagged elsewhere, not cross-browser GA; ship it as a progressive enhancement with a graceful fallback for browsers still behind the flag.1
FAQ
What is CSS Grid Lanes?
CSS Grid Lanes is a new layout mode the Safari team introduced at WWDC 2026 for building masonry-style layouts natively. It sits between Grid and Flexbox: it structures one axis and leaves the other free, distributing items across multiple lanes into a tightly packed, staggered layout that preserves each item’s natural proportions.1
How do I build a masonry layout with Grid Lanes?
Three lines of CSS: set display: grid-lanes, define tracks with grid-template-columns using fr units (for example 1fr 1fr 1fr for three equal columns), and add a gap. Swap grid-template-columns for grid-template-rows to turn a vertical waterfall into a horizontal brick wall. You pick one direction, not both.1
What does flow-tolerance do?
flow-tolerance loosens or tightens the rule that places each item in the shortest column. Pure shortest-column placement can make visual order zigzag away from tab order, which hurts accessibility. With flow-tolerance on, the browser checks whether the taller column is less than the shorter column plus the tolerance before deciding placement, keeping items aligned with reading order until the height gap grows too large. The default value is 1em.1
Can I use Grid Lanes in production today?
In Safari 26.4 it’s available now. Other browsers gate it behind a flag, so Grid Lanes is not yet cross-browser GA. Ship it as a progressive enhancement with a fallback for browsers that still require the flag.1
Does Grid Lanes work with the Grid properties I already know?
Yes. Item-level placement uses existing Grid properties: grid-column: span 2 widens an item, explicit column placement positions it, and grid-template-columns: subgrid folds a nested component’s contents into the parent layout. You control column placement; Grid Lanes decides the row.1
Grid Lanes is the kind of platform addition that deletes a dependency rather than adding one, which is the whole argument of the no-build manifesto and a direct path to the kind of result chronicled in the Lighthouse perfect score writeup. Shipping native, semantic layout instead of JavaScript-rendered grids also keeps your markup legible to machines, the case made in HTML is the format agents want. The full series hub is the Apple Ecosystem Series.
References
-
Apple, WWDC 2026 session 314, Learn CSS Grid Lanes. Source for the Grid Lanes layout mode and its position between Grid and Flexbox; availability in Safari 26.4 and behind a flag in other browsers; the three-line build (
display: grid-lanes,grid-template-columnswithfrunits,gap) and thegrid-template-rowsbrick-wall variant with the one-direction constraint; track sizing with unequalfr,auto-fill, andminmax(); item shaping withgrid-column: span 2, explicit column placement (column not row), andgrid-template-columns: subgrid; the shortest-column placement rule, the tab-order/accessibility problem it creates, andflow-tolerance(default1em) as the dial that loosens or tightens it; and Web Inspector’s Grid Lanes overlay. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩