I saw a great introduction to CSS Grid Lanes, aka Masonry Layouts, by Patrick Brosset at CSS Day 2026. I liked the versatility of its use cases, but I was also concerned that it’s inaccessible by default.
Note:
This post contains interactive demos. If you want to see them instead of screenshots, enable the CSS Grid Lanes Layout flag in Edge or Chrome or use Safari 26.4+ or Polypane 29+.
Intro to Grid lanes
CSS Grid Lanes is a new layout technique in CSS. Although the name suggests it, you don’t create grids with it; instead, you create columns or rows that automatically get populated with items. The layout kinda looks like a grid, but the big difference from regular grids is that you can only control one axis. By default, the browser decides where to place each item: it’s placed in whichever column brings it closest to the start of the container.
HTML
<div class="grid-lanes">
<button class="s">1</button>
<button class="m">2</button>
<button class="l">3</button>
<button class="l">4</button>
<button class="m">5</button>
<button class="s">6</button>
</div>
CSS
.grid-lanes {
display: grid-lanes;
grid-template-columns: repeat(3, 1fr);
}
button { block-size: var(--h)}
.s { --h: 2lh; }
.m { --h: 4lh; }
.l { --h: 6lh; }
.grid-lanes {
display: grid-lanes;
grid-template-columns: repeat(3, 1fr);
gap: var(–oli-g-spacing-s);
background: var(–oli-g-colors-background);
}
.grid-lanes-focus:has(:focus-visible) {
display: grid;
}
.grid-lanes-flow {
flow-tolerance: 0;
}
button { block-size: var(–h)}
.s { –h: 2lh; }
.m { –h: 4lh; }
.l { –h: 6lh; }
.supports-reading-flow,
.supports-grid-lanes { display: none; }
@supports (display: grid-lanes) {
.supports-grid-lanes { display: block;}
.supports-not-grid-lanes { display: none; }
}
@supports not (display: grid-lanes) {
.supports-not-grid-lanes { display: block; }
}
@supports (reading-flow: grid-rows) {
.supports-reading-flow { display: block; }
.supports-not-reading-flow { display: none; }
}
figure p { margin: 0 !important; }
.focus-btn:focus {outline: 3px solid var(–oli-g-colors-cta)}
In the demo above, you can see what makes Grid Lanes special: you can arrange differently sized items in a grid-like fashion with equal gaps.
You may have noticed that the columns in this demo are equal in height. That’s because I arranged them that way, but one of the strengths of Grid Lanes is that you don’t have to care about that. The browser looks at the items you give it and tries to create balanced columns (or rows). It does so by placing items as close as possible to the grid’s start edge.
In the following demo, items 1-3 are each placed in a separate column because this brings them as close as possible to the start of the container. Item 4 is in the second column because that’s the shortest column at the time of placement. The next two columns are equal in height. If there’s a tie, the browser continues from where it left off (column 2 in our example) and places the item in the next available fitting column (column 3). Finally, the last item is placed in the shortest column, column 1.
HTML
<div class="grid-lanes">
<button class="l">1</button>
<button class="m">2</button>
<button class="l">3</button>
<button class="m">4</button>
<button class="m">5</button>
<button class="s">6</button>
</div>
That’s pretty cool, but this strength is also Grid Lane’s biggest weakness. As you can see, the visual order no longer matches the tab order.

That can be a problem, especially when the container spans a larger area on screen. WCAG Technique C27 lists several reasons why:
- A user with low vision who uses a screen magnifier in combination with a screen reader may be confused when the reading order appears to skip around on the screen.
- A keyboard user may have trouble predicting where focus will go next when the source order does not match the visual order.
- If a blind user, who reads the page with a screen reader that follows the source order, is working with a sighted user who reads the page in visual order, they may be confused when they encounter information in different orders.
That’s definitely a problem, but not necessarily a deal breaker. The flow-tolerance property may help improve the situation.
Placement tolerance
The flow-tolerance property allows us to adjust the placement precision. As mentioned, the algorithm places items as close as possible to the start edge. If one column is smaller than the other, the next item will be placed in the smaller column. If a column is only slightly larger, that behavior may result in an order mismatch and in an ugly layout. You’ll see what I mean in the next demo.
We have 4 items. One is much larger than the others, and one is much smaller. The two others are almost equal in height; there’s only a 1px difference.
HTML
<div class="grid-lanes">
<button style="--h: 50px">1</button>
<button style="--h: 60px">2</button>
<button style="--h: 49px"">3</button>
<button style="--h: 20px">4</button>
</div>
CSS
.grid-lanes {
display: grid-lanes;
grid-template-columns: repeat(3, 1fr);
flow-tolerance: 0;
}
button { block-size: var(--h)}
Item 4 ended up in the third column because item 3 is 1px smaller than item 1. That’s only happening because I set flow-tolerance: 0. The default value is 1em. If I increase the tolerance or use the initial value, you can see how item 4 ends up in the first column. That’s because the property specifies what the threshold is for considering tracks to be “the same height”. If you set the value to 10px, a smaller column has to be at least 10px smaller to be considered smaller.
flow-tolerance: 1px we get a different layout.When the logical and visual orders are out of sync, you can increase the Flow Tolerance to mitigate the mismatch. That sounds like a solution to the problem, and it is for some (most?) layouts. The thing is, that the tolerance value sometimes needs to be very high to make a difference.
Demos
The WebKit team created The Field Guide to Grid Lanes, a demo and playground for CSS Grid Lanes. What they build is cool and useful, but all their demos would fail WCAG 2.4.3 by default if they contained focusable elements, which in a realistic example they most likely would.
Their first demo is a classic image gallery with images of varying heights. The numbers you see on each image indicate its position in the DOM within the container. The order of the first 5 items is fine, and we also know why, but starting with item 6, things get ugly. There is a critical mismatch between the DOM and the visual order.

The Field Guide comes with controls for each demo. You can increase the Flow Tolerance with a range slider that goes up to 10rem. With a Flow Tolerance of 10rem, it’s slightly better but still not acceptable.

I had to increase the Flow Tolerance to 40rem (640px) to remove the mismatch entirely. Unfortunately, that surfaced another problem. The lengths of the columns are now imbalanced, and because the heights of the images are so different, focus still jumps around a lot, but now vertically. For example, you can see how the focus has to travel down from item 11 to 12, then up to 13, and down to 14. That’s not great.

To be fair, although all their demos fail WCAG by default, increasing Flow Tolerance sometimes fixes the problem. In the following screenshot (click to enlarge), you can see an order mismatch across all screen sizes.
Setting the Flow Tolerance to 10rem, gets rid of most issues.
Update:
- As Patrick pointed out on Bluesky, you can also set
flow-tolerancetoinfinite, which makes items distribute themselves strictly in order, without considering the length of the tracks at all. - Clarified that the Field Layout demos don’t fail 2.4.3, but would if they contained focusable elements.
Reading flow
Of course, I’m not the first to address this issue. There has been a lot of discussion, even dating back to when CSS Grid Layout was proposed. If you’re interested, check out Adrian Roselli’s post Source Order Matters for a chronological overview or read the following issues on GitHub:
- Masonry layout in CSS Grid 3 has potential to cause accessibility problems with reading order.
- Providing authors with a method of opting into following the visual order, rather than logical order.
There is awareness of this problem, and people have been discussing it a lot; the outcome was two new properties in CSS: reading-flow and reading-order. I won’t go into detail now, you can read about them on the Chrome blog or MDN, but essentially, the reading-flow property can be used to ensure the reading and tabbing order reflects the visual order when the visual and DOM order don’t match.
Note:
Switch to a Chromium-based browser like Edge or Chrome to see an interactive demo.
Let’s say we have a grid like in the following example, where there is a clear mismatch between the visual order and the DOM order. When you press Tab, focus moves to the first, second, third, and finally the fourth item, following the logical order but not the visual order.
.reading-flow { background: var(–oli-g-colors-background); display: grid; grid-template-columns: repeat(3, 1fr); gap: var(–oli-g-spacing-xs)}
.reading-flow-fixed { reading-flow: grid-rows; }
CSS
.reading-flow {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
HTML
<div class="reading-flow">
<button style="grid-column: 2 / -1">1</button>
<button>2</button>
<button style="grid-column: 1; grid-row: 1;">3</button>
<button style="grid-column: 1 / span 2; grid-row: 2;">4</button>
</div>
To fix that issue, you can set reading-flow to grid-rows. Now the reading order and focus order follow the visual order.
CSS
.reading-flow {
display: grid;
grid-template-columns: repeat(3, 1fr);
reading-flow: grid-rows;
}
Reading flow could address many of the issues (not all, because visual jumps could still be present) I described in this blog post, but it’s still theoretical: it’s only implemented in Chromium-based browsers and doesn’t yet work with Grid Lanes. Also, the positions of WebKit and Mozilla aren’t clear. Safari still has some concerns and open issues, and Firefox hasn’t published its position yet.
I haven’t been following the discussions around Reading Flow, and I haven’t played with it yet. Not having spent too much time thinking about it, I’m a bit torn. On the one hand, Reading Flow seems to work and fix a real, common issue. On the other hand, it may lead developers to care even less about source order. Anyways, this post isn’t the right place to discuss that, but I feel like it could be a good idea to set an implicit default value for Grid Lanes that follows the visual order, since Grid Lanes inherently break the tabbing order. That may not be a good idea, and it may not be possible, because there are different ways to lay out Grid Lanes, but as this blog post has shown, the default state is unacceptable in many cases. If you have ideas on how to address this issue, please add your opinion to one of the issues I linked, create your own issues or bug reports, or talk to browser people on social media.
The title of this post
Consequently, today, that means that if the heights of your grid items don’t vary too much and if you increase Flow Tolerance, which you probably always have to do, you can make Grid Lanes more or less accessible. In the future, when all browsers support reading-flow and implement it for Grid Lanes, it may get even easier and you may not have to rely on flow-tolerance too much.
Now you may ask yourself, why is the title of this post still so negative? Why didn’t I go for something like “Improving the accessibility of Grid Lanes“?
-
It’s too easy to create inaccessible Grid Lanes if you aren’t aware of the implications. That’s a big difference compared to regular grids because, to mess with them, you have to change the order or explicitly place items, which, by the way, is also possible with Grid Lanes and can potentially make the situation even worse.
-
I watched a talk by Rachel Andrew in which they explain that they didn’t want Grid Lanes to ship unless Reading Flow existed for the reasons described in this post, but that’s exactly what happened in Safari. It supports Grid Lanes, but not Reading Flow. Chrome and Edge support
reading-flowand Grid Lanes behind a flag, but as of today, Reading Flow is scoped to regular grids and flex containers. -
Since Reading Flow for Grid Lanes is only an idea, and Safari made Grid Lanes very real by shipping it, we’re left with Flow Tolerance for improving accessibility. Based on my limited research and experience, the default value for
flow-toleranceseems too low. It should be high by default to reduce the likelihood of a mismatch between the logical and visual order. -
Flow Tolerance is not a silver bullet, and DOM order is not the only thing that matters. Large differences in height between grid items can also affect keyboard accessibility.
-
The specification has a section about accessibility, but it’s not detailed enough.
-
The WebKit field guide has nice demonstrations, but doesn’t address the obvious accessibility issues or reading-flow as a possible solution. They only mention that spanning and explicit placement can be problematic. I find that questionable. The fact that their website isn’t WCAG-compliant doesn’t make it better.
Bonus: Another solution
I’m not sure I really want to recommend this solution, or even if it’s a solution, but I was trying to figure out whether there is a way to improve the situation for keyboard users. And I tried the following, which surprisingly works.
CSS
.grid-lanes:has(:focus-visible) {
display: grid;
}
You can have your Grid Lanes in any order you want, because as soon as there is focus within, the display switches to grid for keyboard users. Of course, that doesn’t fix the problem for sighted screen reader users who use the virtual cursor, and it can also be confusing if the layout suddenly changes on focus. I’m mentioning it because I find the idea interesting, and it can be a solution for some layouts.
Conclusion
I was never really excited about Grid Lanes to begin with, but that was just my personal opinion. After watching Patrick’s presentation, I can see how there are more use cases than the classic Pinterest layout, but still now I’m even less excited due to the potentially poor baseline accessibility. And I’m afraid most people will use them out of the box without adjusting the Flow Tolerance or testing them with the keyboard or screen readers.
To sum it up, my recommendations are:
- Always test your Grid Lanes with the keyboard or a screen reader at different screen sizes.
- If you find a mismatch between the DOM and the visual order, increase the
flow-tolerancevalue. - As soon as it’s available, try to use
reading-flowinstead. - If that doesn’t work, consider using a regular grid.
My blog doesn’t support comments yet, but you can reply via [email protected].

