CSS Grid L3 Masonry Layout Performance Analysis

Elika J. Etemad (fantasai), Apple

Google raised some concerns wrt performance in Masonry Layout:

This document characterizes these concerns more precisely.

Intrinsic Track Size Performance

Because Masonry requires tracks to be sized before items can be placed, intrinsic track sizes such as auto/min-content/max-content cannot depend on placement. Therefore, the current spec defines intrinsic track sizing to assume every auto-placed item exists in every possible track position. The nominal performance of this is Ntracks × Nitems.

However, auto-placed items of a given span size can be grouped and handled as an aggregate item, which brings the performance down to Ntracks × Nspans in the worst case, where Nspans is the number of different span sizes (span 1, span 2, span 4, span 9, etc.) of the items in the grid—and is therefore strictly less than or equal to Ntracks.

Keep in mind the passes here are shallow: we’re not re-doing layout on each of these, we’re just need to aggregate some cached measurements: the min-content, max-content, and minimum sizes of the items.

Optimizations for Intrinsic Track Sizing

Optimizing gets us to where the most common cases are as fast as they would be under Google’s proposal, but additional patterns are nonetheless possible.

We only get worst-case performance if we have mixed track sizes and intrinsic track sizes, and spanning items of various spans and auto-placement. And the extra cost is limited by the number of different span sizes (which is typically small).

Submasonry Sizing Performance

As Ian noted, subgridded masonry can create sizing behavior that is exponential wrt depth of submasonry. With the above optimizations, this only creates a problem if:

If we think this is something that needs to be mitigated, we can apply limits such as “auto-placed submasonry items cannot contribute to their parent grid track sizes”.

We don’t anticipate many use cases for nesting intrinsically sized auto-placed masonry within auto-placed masonry. But intrinsic sizing and explicit placement might be reasonably used in a submasonry that's used as an explicit layout grid without row alignment.

Dense Packing Performance

The grid-auto-flow property allows for opting into a dense packing mode. Variable-size columns (whether intrinsically sized or not) create performance problems for dense packing, since fitting into gaps requires knowing the height, which can depend on the width, which can vary. That means doing re-doing layout at each possible width and then scanning existing gaps created by spanners for one that's big enough.

Our current proposal is to use a heuristic in which we compute the height against the widest and narrowest columns only, and use the tallest such height to find potential slots to test-fit. This will reduce the extra layout passes to 2, at the expense of sometimes missing the ideal dense-packing fit.

Google’s proposal is to disallow dense packing in masonry layouts altogether, which we could also consider. The primary downside of Grid integration here (vs separate display mode with its own properties) is that there’s a slight Web-compat risk to enabling it later if we want to, since we’d be re-using existing Grid syntax rather than minting new Masonry syntax for it.