Your Grid Lanes will likely fail WCAG 2.4.3

eustoria1 pts0 comments

Your Grid Lanes will likely fail WCAG 2.4.3 - Manuel Matuzovic

-->

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:<br>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

CSS

.grid-lanes {<br>display: grid-lanes;<br>grid-template-columns: repeat(3, 1fr);

button { block-size: var(--h)}

.s { --h: 2lh; }<br>.m { --h: 4lh; }<br>.l { --h: 6lh; }

Demo: Items stacked from left to right, from top to bottom

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

Demo: The lengths of the columns are as equal as possible with the downside that items are out of order

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.

Tabbing order is correct for the first 3 items, but then it goes from column 2 to 3 to 1.

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

CSS

.grid-lanes {<br>display: grid-lanes;<br>grid-template-columns: repeat(3, 1fr);<br>flow-tolerance: 0;

button { block-size: var(--h)}

The logical order would be correct and it would look nicer if item 4 was in the first column.

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.

With 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...

grid column lanes order items item

Related Articles