Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-grid-3][masonry] Masonry Syntax Debate #11243

Open
fantasai opened this issue Nov 19, 2024 · 12 comments
Open

[css-grid-3][masonry] Masonry Syntax Debate #11243

fantasai opened this issue Nov 19, 2024 · 12 comments
Labels

Comments

@fantasai
Copy link
Collaborator

fantasai commented Nov 19, 2024

The CSSWG's masonry layout draft includes two competing syntax proposals for the feature. There has been a lot of discussion between the two, and there's an overview of the debate in the TAG review issue.

Opening this issue to focus on the syntax question, since the previous issue debating two possible models started with focus on the performance implications of mixed track sizing, etc. that are no longer relevant.

Key links (primary in bold):

@fantasai fantasai added Agenda+ css-grid-3 Masonry Layout labels Nov 19, 2024
@astearns
Copy link
Member

A couple of questions for folks to (maybe?) spark some discussion:

  • What is the strongest argument for the option you do not prefer?
  • If you have changed your opinion from one of the options to the other, what was the reason for the change?

@astearns
Copy link
Member

TAG feedback: w3ctag/design-reviews#1003 (comment)

@nathanchase
Copy link

FWIW: I still agree that in isolation, display: masonry makes more sense due to its brevity, but a lot of the points brought up by @jensimmons (https://webkit.org/blog/16026/css-masonry-syntax/) and @shadeed (https://ishadeed.com/article/css-grid-masonry/) convinced me that the overall context shift is higher to create new keywords, recall syntax differences, and set up default values that could potentially have highly unintended results. Particularly, this matrix is compelling:
image

With that in mind, and with the also welcome shift away from using "masonry" as a term and instead leaning on the existing "collapse" keyword already found elsewhere makes a lot more sense for the future.

@kizu
Copy link
Member

kizu commented Dec 4, 2024

If we were to choose from the two options presented, I prefer the “Just use Grid” option.

I have a bigger take on this, which I just can't find an opportunity to write up properly, but the gist is that with masonry we're mixing two things: one-dimensional layouts (without the masonry specifically, as a wider feature), and the masonry auto-placement algorithm. I'd want the first feature as a part of a CSS grid, regardless of the masonry. Then, having one-dimensional grids, introducing an alternative placement algorithm in addition sounds like a reasonable iterative approach.

I am against the display: masonry for the reasons presented by Jen and Ahmad, specifically the fallbacks and conditional adjustments aspects. It is much easier to adjust or create a fallback for something when you don't have to change N different properties at the same time. I would prefer learning a slightly different syntax for specific cases rather than an additional set of slightly different properties.

What is the strongest argument for the option you do not prefer?

I agree with the arguments for the grid-independent option about good defaults and shorthands. However, I can see a future where, instead of putting the current flawed grid aside and giving up on it in favor of a new system, we could see if we could improve what we have. With new keywords added to the mix, they allow us to change the way shorthands behave, and design things better. It is true that authors rarely use the grid shorthand, and that means that we should look into how we could improve it for all the cases.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Masonry Syntax Debate.

The full IRC log of that discussion <fantasai> Topic: Masonry Syntax Debate
<fantasai> github: https://github.com//issues/11243
<fantasai> alisonmaher presenting from Chromium team
<fantasai> alisonmaher: [intros the topic]
<fantasai> alisonmaher: Several properties behave differently in each, or don't apply, so we think a new display type would be better.
<fantasai> alisonmaher: Plus we can define a better default value for the template tracks, creating an automtical masonry instead of a single column
<fantasai> alisonmaher: Regarding grid fallback, needing one is a temporary problem, so should focus on the future
<fantasai> alisonmaher: authors should make explicit fallback, to avoid surprises
<fantasai> alisonmaher: Positioning in masonry is simpler than grid, it's only placed in 1 axis instead of 2
<fantasai> alisonmaher: Grid is confusing because authors might make a mistake about which axis they are placing in (rows vs columns)
<fantasai> alisonmaher: separate model only has one axis
<fantasai> alisonmaher: this allows switching the axis easily
<fantasai> alisonmaher: Shorthands also are better with separate shorthand. Grid shorthand is complicated, hard to use. Masonry shorthand is easier because don't need to remember the order
<fantasai> alisonmaher: placement works differently in grid vs masonry
<fantasai> alisonmaher: dense packing is also different : for grid can place in any empty slot, but due to perf considerations for masonry current proposal restricts to same-sized track
<fantasai> alisonmaher: masonry also has different intrinsic sizing rules, with auto-placed items affecting all auto-sized tracks not just the one they end up in
<fantasai> alisonmaher: alignment is also very different, open questions about how this works in the masonry axis
<fantasai> alisonmaher: this means grid and flexbox are quite different in how they behave
<fantasai> alisonmaher: in masonry layout auto-placed subgrids don't inherit line names
<fantasai> alisonmaher: we expect there to also be other changes for submasonry/subgrid that will lead to divergences
<fantasai> alisonmaher: Integrating masonry into grid will lead to spec bloat, will be harder to teach, and lead to developer confusion
<fantasai> alisonmaher: Conclusion: masonry should be a separate display type
<fantasai> jensimmons: [intro slide]
<fantasai> jensimmons: At this point decision is about syntax -- mental model. Behavior is same in both.
<fantasai> jensimmons: [reviews basic case]
<fantasai> jensimmons: Choice to Just Use Grid is extending Grid L1. [shows example of grid vs masonry photo grid, with one difference - the grid-template-rows: collapse line]
<fantasai> jensimmons: New layout type, creates a separate tool with separate syntax that's similar but not the same as what exists
<fantasai> jensimmons: [shows table of properties being added]
<fantasai> jensimmons: We don't believe there's a compelling argument to add so many new properties to CSS
<fantasai> jensimmons: Both have properties for defining tracks; defining masonry axis
<fantasai> jensimmons: both have ways to define placement, and both have a new slack property
<fantasai> jensimmons: both have shorthand, and a gap property
<fantasai> jensimmons: and both have ways to implicitly size tracks
<fantasai> jensimmons: more significant difference is grid-auto-flow vs masonry-direction/fill/flow
<fantasai> jensimmons: Chromium argues that their new syntax is more understandable. We disagree, just use grid-auto-flow
<fantasai> jensimmons: Other major difference is template syntax
<fantasai> jensimmons: Here's a column example using the templat syntax. identical in grid 1, and masonry in both
<fantasai> jensimmons: When you layout rows in grid, template syntax is a bit different -- you stack the template names to phyiscally diagram the names for the rows
<fantasai> jensimmons: Just Use Grid re-uses this syntax exactly; but new masonry layout uses the column syntax for rows.
<fantasai> jensimmons: Chrome believes it's less confusing to use the same syntax in rows vs columns; but we believe it's better to use the same syntax between grid rows and masonry rows
<fantasai> jensimmons: Other difference is the auto-flow -- grid's indicates the primary fill direction, Chrome believes this doesn't make sense and changed it to match the orientation of lines
<fantasai> jensimmons: Debatable which is better. Might make sense if we had time machine, but is it worth creating a new layout API for this ?
<fantasai> jensimmons: Lots of subtle differences are likely to trip people up. They're familiar but not quite the same.
<fantasai> jensimmons: We shouldn't fork grid, would be confusing to authors.
<lea> q?
<lea> q+
<fantasai> jensimmons: Chrome argues that new display type allows better defaults -- but the defaults propose aren't good
<fantasai> jensimmons: if you think through the default they propose, it doesn't quite work as easily as claimed [see article]
<fantasai> jensimmons: requires deep understanding of autosizing
<fantasai> jensimmons: We believe it's better to just use grid. Very simple, one new value, re-uses syntax and mental model makes easier to learn
<fantasai> jensimmons: also easier to switch, e.g. at breakpoints or progressive enhancement
<fantasai> jensimmons: follows CSS design principles to re-use what already exists
<fantasai> [end presentations]
<fantasai> astearns: If you have comments, please add yourself to the queue
<astearns> ack lea
<lea> https://github.com/w3ctag/design-reviews/issues/1003#issuecomment-2489688718
<fantasai> lea: We did a TAG review on this
<fantasai> lea: My opinion is fully reflected there. I think the arguments WebKit team makes are compelling.
<oriol> q+
<fantasai> lea: We thought not only should masonry be part of grid, but should go further.
<fantasai> lea: a lot of arguments for integrating is that "grid is too hard". In that case we should make grid things easier.
<astearns> q+
<fantasai> lea: complex things are possible, but simple things are not so easy
<fantasai> lea: Big part of Google's argument is defaults, but we could just have smarter defaults -- there is precedent for this in CSS
<fantasai> lea: if we decided that would help ergonomics
<TabAtkins> q+
<fantasai> lea: We agree that switching between grid vs masonry is common. Grid might be a slightly better fallback than nothing, but minor argument because ppl can use @supports
<fantasai> lea: Introducing all these new properties increasing the API surfaces that authors need to learn. Less they can port over.
<fantasai> lea: Even if we say we will be disciplined, experience shows that we won't. Even if not intentional, accidental.
<fantasai> lea: DRY - don't have multiple sources of truth
<miriam> q+
<fantasai> lea: One of arguments against masonry in grid is that grid's are 2D, but actually in graphic design grids were often 1D
<fantasai> lea: I agree that most masonry use cases need simpler grids than general grid use cases
<fantasai> lea: but that means we should make those grids easier to define for both grid and masonry
<fantasai> lea: the more we looked into this, we realize there are 3 different layout modes that give you 2D arrangement of children
<fantasai> lea: we recommended not just make masonry part of grid, but find ways of integrating what we already have better
<fantasai> lea: could we come up with a shorthand that sets grid-auto-flow and flex-direction, and promote that for layout direction in general?
<fantasai> lea: then authors only need to learn one control for it
<fantasai> lea: another concern was overfitting
<fantasai> lea: it doesn't cover a lot of cases that look like masonry, like Flickr-style grid
<fantasai> lea: it's like a horizontal masonry
<astearns> ack oriol
<fantasai> oriol: Problem with jensimmons's reasoning
<fantasai> oriol: She said the proposed masonr-direction property would be new syntax that doesn't match grid-auto-flow property
<fantasai> oriol: but this property matches flex-direction property
<fantasai> oriol: so instead of trying to be close to grid, tries to be close to flexbox
<fantasai> oriol: closer to grid is a choice, could be consistent with different things
<fantasai> astearns: One question I asked is, has anyone changed their mind on which proposal they support?
<fantasai> astearns: I personally have. I thought that separate display property made a lot more sense, in terms of designing the feature and I was very daunted by the idea that we'd have to consider both grid and masonry for any new development ineither
<fantasai> astearns: seemed sticky to me
<fantasai> astearns: but the TAG argument convinced me that we should do the work of integrating these things
<astearns> ack TabAtkins
<fantasai> TabAtkins: Thanks for setting that up for me, because I'm going to refute the TAg argument! I think they're wrong in this case
<astearns> ack astearns
<astearns> zakim, close queue
<Zakim> ok, astearns, the speaker queue is closed
<fantasai> TabAtkins: You can draw a lot of surface-level connections between Grid and Masonry, and Flexbox, and other hypothetical layouts
<jyasskin> q+
<fantasai> TabAtkins: but when you actually look at details of how they work, behaviors each one is capable of, they're pretty distinct
<fantasai> TabAtkins: if you try to combine together, it would be an unholy mess of conflicting constraints -- e.g. flexing in items of masonry or grid
<fantasai> TabAtkins: or you'd have a weird mish-mash of, "the 2D layout", but if you call it a flex you get access to these properties, call it grid, access to these other properties
<fantasai> TabAtkins: concrete example, "pillar" example mentioned in webKit blog post, that wasn't compatible with the base concepts in masonry and flex because it wants a shared block formattng context
<fantasai> TabAtkins: grid etc have different formatting contexts, can't use floats
<lea> actually, the TAG argument was that layout seems to actually be a continuum, and syntax should accommodate that rather than forcing one of two extremes (current flex vs current grid).
<fantasai> TabAtkins: they're specialized for what makes sense
<fantasai> TabAtkins: You can occasionally merge things together, but definitely not something you can do that by default
<fantasai> TabAtkins: too distinct to be merged in a reasonable way
<jensimmons> That's why the "pillar" example will use `display: block`. The argument being made when it was articulated is NOT that it should be part of Grid, but that it should be part of Block, and not it's own yet another new mode.
<lea> Our argument was not "make it a part of grid" per se, but more "don't introduce a completely parallel new thing". If you can extend flex so that masonry can become part of that, that's just as fine
<fantasai> TabAtkins: Then usability arguments.
<lea> q+
<fantasai> TabAtkins: The masonry shorthand can be very similar to a standard CSS shorthand -- fully reorderable, just put the bits you care about
<fantasai> TabAtkins: integrated one, the grid shorthand is very complex, mixing in masonry doesn't make it simpler
<fantasai> TabAtkins: would stay bad and get worse
<fantasai> TabAtkins: separating lets use design things catered to the use case
<lea> if the `grid` shorthand has poor usability we should improve the grid shorthand, not design a new thing :)
<astearns> ack miriam
<fantasai> miriam: Like Alan, tend to agree with TAG on this. I'm not real excited about a future where we keep inventing new layout modes with slight differences.
<TabAtkins> The `grid` shorthand is complex *intrinsically*, it's got a lot of concepts that have to all be put together. It can't really be made much better.
<astearns> ack dbaron
<fantasai> miriam: I get that there's complexity, but it's worth the attempt to figure out how to not invent new tracks every time we have a new layout that has tracks
<TabAtkins> And that intrinsic complexity is directly tied to it being an inherently 2d layout mode, whereas Masonry, like Flex, is "1d, plus a bit"
<fantasai> dbaron: I remember Ian arguing about the perf characteristics wrt intrinsic size calculations
<fantasai> dbaron: Was related to fundamental ordering between how parts of the process run in grid vs masonry
<fantasai> dbaron: Good perf important for end users. Is that topic still under debate? Or is masonry in grid syntax using the model that Ian wanted
<fantasai> TabAtkins: Whether in grid syntax or not, using the distinct layout rules we defined to work for it
<fantasai> jyasskin: Wanted to emphasize a couple aspects of TAG review
<fantasai> jyasskin: It seems really nice to keep the property from Chrome proposal that you don't have to learn both, can just learn to do masonry without learning all of Grid
<fantasai> jyasskin: even if that's in a unified system
<fantasai> jyasskin: perhaps still define masonry shorthand, and have it set grid properties
<jensimmons> To create a simple masonry-style layout in Grid, you just need 3 lines of code (4 with a gap). It's quite simple.
<fantasai> jyasskin: Most consensus part of TAG feedback was to share properties whenver possible
<lea> q+
<fantasai> jyasskin: Not necessary to share the same 'display' values; could define different 'display' values but share the properties.
<fantasai> jyasskin: One thing we didn't like about unified proposal was `grid-auto-flow` in the unified proposal, where some values were ignored.
<TabAtkins> Yeah, this is the usability point I'm pounding on
<fantasai> astearns: I'm not hearing a way forward yet. At some point, one of the camps is going to have to concede in order to move this forward.
<fantasai> lea: What if we do a straw poll. Not to decide, but to figure out how far are we from consensus?
<fantasai> +1 lea
<fantasai> lea: people may have been convinced
<fantasai> POLL: 1) Just Use Grid 2) New Masonry Layout
<TabAtkins> 2
<lea> 1
<fantasai> 1
<kizu> 1
<oriol> 2
<bts> 1
<alisonmaher> 2
<jensimmons> 1
<masonf> 2
<florian> 1
<miriam> 1
<ethanjv> 2
<JaseW> 1
<astearns> 1 (changed from 2)
<dbaron> abstain
<ydaniv> 2
<rachelandrew> 2
<dholbert> 2 (weak preference)
<gfaujdar> 1
<chrishtr> 2
<SebastianZ> 2
<jfkthame> 1
<bramus> abstain
<kbabbitt> 2
<joshtumath> 2 (but being persuaded)
<schenney> 1 but try to move toward common property names
<noamr> abstain (happy if we ship either!)
<jyasskin> I would love to see both camps' attempts to move a step closer to a shared understanding. e.g. Do the WebKit folks think it makes sense to define a masonry: shorthand in the grid-unified proposal? Can they fix grid-auto-flow? Do the Chromium folks see some properties that could be more shared?
<romain> 1 (changed from 2)
<emilio> 1.5
<fantasai> jensimmons: Personally disappointed that we're not making more progress. We've been having this argument for 5 years.
<fantasai> jensimmons: We have two implementations. We'd like to ship. Lots of discussion over the last year.
<fantasai> jensimmons: Many folks have strong opinions, but the target keeps moving. A lot of the concerns have been addressed, but new reasons to keep separate.
<TabAtkins> I mean, same.
<fantasai> jensimmons: Argument is no longer about technical details, but overall concept and authoring experience.
<JaseW> Are Jen's slides available anywhere?
<fantasai> astearns: I believe both camps want to ship and are frustrated with current impasse.
<rachelandrew> not new reasons here, same reasons I started with (before I was at Google)
<astearns> zakim, open queue
<Zakim> ok, astearns, the speaker queue is open
<fantasai> jyasskin, yes I think we could do that. Not sure it would convince the Chrome folks though :)
<JaseW> @jensimmons

@astearns astearns removed the Agenda+ label Dec 4, 2024
@astearns
Copy link
Member

astearns commented Dec 4, 2024

@JoshTumath
Copy link

JoshTumath commented Dec 6, 2024

Now that I've had more time to consider the opinions raised in our call on Wednesday – and particularly the TAG review which @LeaVerou shared – my mind has changed and I have swayed towards the 'Just use grid' option. I'll explain why.

The TAG viewpoint set us a new north star to aim for where all layout methods that do a '2D arrangement of children' become more unified and easier for authors to declare:

Overall, we think masonry, grid, and wrapping-flexbox should be incorporated into a unified set of properties.

This argument was particularly compelling to me (emphasis added):

  1. It was argued that the grid-independent syntax makes things easier if the properties need to diverge in the future. We think that is a drawback of that syntax, not a feature. Even if the WG selects a syntax like the grid-independent one, it should work hard to ensure that the properties diverge as little as possible in the future, even if some masonry properties initially appear not to have an obvious behavior for other display modes. It would be even worse to evolve subtle variations in patterns that otherwise appear to match, for example by forgetting to apply a new grid keyword to the parallel masonry property.

This argument trumped my main concerns around how we might want the syntax to diverge. The argument also supported the vision that the WebKit team gave us at the end of their blog post about a possible future where we could even somehow use the grid properties on flow layouts.

And then the TAG review goes on to talk more broadly about layout syntax.

We urge the WG to explore ways to unify these so that authors can port more knowledge from one to the other (even if they are implemented as separate code paths internally). For example grid-auto-flow, flex-direction, masonry-direction, and masonry-fill all control the same stylistic aspect from an author pov and it seems that they could be more unified to some degree.

[...]

These patterns blur the line we've been assuming between 1-d and 2-d layout, and the WG may need to solve the problem by leaning into a continuum between those two options. It would be ideal to find a set of properties that can be used to build all of these layout patterns, instead of potentially overfitting to just masonry layouts.

In conclusion

On behalf of the BBC, I am happy to support the "Just use grid" syntax to move the proposal forward.

However, the TAG review has set out a wider vision for shorthands or other more generic syntaxes for defining layouts. Would it be helpful, as part of this issue, to start blue-skying those, just to help the debate along? I would be interested to see any proposals.

For example, the fact that we can now use gap in flex layouts and align-content in grid, flex and now flow layouts has been a game changer. It would be great to see how some of the grid-* properties could be made more generic. Like @kizu said, 'It is true that authors rarely use the grid shorthand, and that means that we should look into how we could improve it for all the cases.'

@Monknow
Copy link

Monknow commented Dec 6, 2024

I am an outsider here, but wanted to give my grain of sand from an author's point of view. I don't want to get into which proposal will be easier to define in the spec or implement in browsers since that's something that most developers aren't aware of but rather boil it down to what syntax developers will find easier to learn and use, and if the future gives us more layouts like the Webkit post suggests, which will make it easier for developers to learn to new layouts.

Prefixes and extra properties

One of the main arguments for the Just Use Grid team is the enormous amount of similar properties that would need to be added to CSS.

image

By the WebKit Post:

One of the guiding principles that drives decisions at the CSS Working Group is to always strive to reuse existing patterns and properties when creating new possibilities.

When multicolumn was invented, a new column-gap property provided a way to define the space between columns. A decade later, when the CSSWG needed a way to define space between grid columns, the column-gap property was repurposed. It got a corresponding row-gap property and a new shorthand, gap, to be more universal, and eventually made its way to Flexbox as well. It took a couple of tries, but the CSSWG realized it would be a mistake to keep creating separate gap properties for different contexts — column-gap + grid-gap + flex-gap… It’s better to repurpose what already exists.

By the same logic, it isn't a problem of new properties with a masonry- prefix, but of the prefixes altogether. If we are thinking about defining new layouts, then the grid- prefix is also a reusability antipattern. I keep thinking that, just from a syntax standpoint, it should be possible to use a new unprefixed template-areas property for masonry and grid, regardless of the formatting contexts.

If we look at another example given in the WebKit post:

image

According to the Chrome proposal, this type of layout would have its own prefix, but I think everyone would agree it would be hellish to also have pillar- or new-layout- prefixed properties, and so on if future layouts are added.

Onto the Webkit argument, they say that maybe in the future this layout could be achieved with a snippet like the following:

article {
  display: block; /* default value, unnecessary to state */
  grid-template-columns: 1fr 1fr minmax(15ch, 30ch) minmax(15ch, 30ch) 1fr;
  grid-default-column: 3 / 5;
}

But to me, it feels unnatural to use grid- prefixed properties for things that aren't grid. That's why I think removing prefixing altogether is an option to consider. The grid- prefixed properties would still work for backward compatibility, but you could also use the unprefixed version. Maybe properties that only work in their corresponding formatting context would remain prefixed, but overall, it would reduce the number of properties to add and the syntax to remember.

If the conversation is focusing on unifying, then I just wanted to bring this to the table, but I must say that I am ignorant of the consequences and implications of this. Just a not-that-technical developer's point of view of what I would like to code in the future :)

@tabatkins
Copy link
Member

tabatkins commented Dec 27, 2024

I've been sitting on this for a bit, because of vacation/Christmas/etc., but I think it's ready to post now.

tldr: The "reuse when possible" principle is completely valid and should be (and is) applied as much as possible, but it shouldn't be overused, when merging/reuse is messy or complicated. Grid/Masonry is an example of the latter, with several properties that work well in Grid but are genuinely bad when used for Masonry, and several other properties that are at least clumsy in Masonry (tho technically usable). This appears to be a general issue, since Flexbox can't meaningfully merge into these either, nor can future examples that have been brought up.

In short, while new layout abilities sometimes merge nicely into an existing layout mode (like Subgrid into Grid), it is usually the case that the abilities of one layout mode, and the specialized syntaxes we design to allow authors control over those abilities, are usually a bad fit for even a moderately different layout mode. Layout modes should, in general, get their own set of properties with their own specialized syntaxes, rather than trying to reuse each other's properties.

I'll go into detail on exactly how the current Grid-masonry design is bad, and at the end, offer a compromise if the WG still disagrees that Masonry should be its own independent layout mode.

Specific examples

Apologies for the length of this section. The badness really is in the details; the way that the Grid properties work when applied to Masonry is an extraordinarily bad design, and it's worth working thru those details rather than handwaving it as "it's bad, just trust me". If you'd prefer to trust me, feel free to skim.

  • grid-template-areas:

    • Syntax allows defining an NxM grid; when used in Grid-masonry, we are forced to ignore all but the first row/column. "Technically valid but ignored" values are an anti-pattern we try to avoid when possible; we often purposely design grammars to avoid this even being possible.

    • A single-column Grid-masonry and a single-row Grid-masonry use different syntaxes; "one two three" vs "one" "two" "three". Requiring authors to remember which syntax to use depending on their masonry direction is bad.

      In Grid, the syntax works well, and authors have good reason to break the separate row-strings onto separate lines, to align the columns across the strings and make 2D ASCII art showing the grid structure. There is no such benefit in Grid-masonry (there's only one cell per row), so instead you just have the value put on one line regardless, and the weird syntax split based on direction.

      That is, authors are not going to write:

       grid-template-areas: "foo bar baz"; // column masonry
       grid-template-areas: "foo"
                            "bar"
                            "baz"; // row masonry

      as that's just a frankly silly use of linebreaks/whitespace. They'll just write:

       grid-template-areas: "foo bar baz"; // column masonry
       grid-template-areas: "foo" "bar" "baz"; // row masonry
  • grid-auto-flow:

    • Grid 2 syntax is [ row | column ] || dense. In Grid, this dictates how auto-placed items search for empty spaces - by scanning each row before moving to the next, or scanning each column. Both row and column do absolutely nothing in Grid-masonry; it's already intrinsically auto-placing, and only has one possible axis to do it in. (While dense originally did nothing in Masonry either, we've since come up with a behavior for it, tho it's less powerful than the Grid behavior.)

    • Grid 3 adds row-reverse, column-reverse, and wrap-reverse. For Grids, the first two are the same as row/column, but flip the direction you fill the rows/columns in; the third flips to make it fill in the last row/column first and wrap back toward the start when you need more rows/columns.

      In Grid-masonry, we first have the issue that row-reverse and column-reverse again do the exact same thing, because the "auto flow" direction is already fixed. They do finally have an effect, tho, which is vaguely similar but notably distinct from their effect in Grid: rather than changing the direction you search for holes, it changes which direction you favor when breaking ties for "shortest track". Note that while row vs row-reverse in Grid will have a pretty large effect on the layout, in Grid-masonry it might only have an effect on the first items to be placed (since all tracks are tied initially); afterwards, if there aren't any ties it does nothing.

      Grid-masonry's wrap-reverse is more similar to Grid's in effect and impact, as it causes the tracks to fill from their end side. The name is a little misleading, however; there's no real notion of "wrapping" in Masonry (while it makes perfect sense in Grid).

      The display:masonry properties are much clearer; they borrow their names and syntax from Flexbox, which has similar concepts: just like Flexbox's flex-direction: row | column | row-reverse | column-reverse, we have masonry-direction: row | column | row-reverse | column-reverse, with very similar behavior. Then the one novel property in this group, masonry-fill, determines how it breaks ties, a situation/behavior that neither Flexbox nor Grid really has.

  • the grid-template shorthand:

    • In Grid, this combines grid-template-rows/grid-template-columns and grid-template-areas. Grid-masonry, thus, inherits all the problems of those properties: only one of -row/-columns is used (the other needs to specify masonry), and the -areas component has its two distinct syntaxes. The combination actually compounds the badness, tho.

      First, the -rows/-columns components are in a specific order in Grid: the rows, then the columns. This order is, again, completely sensical in Grid, as it corresponds to how you write the 2d grid in ASCII, but in Grid-masonry it's an unnecessary requirement. So a row-masonry needs to be written repeat(3, 1fr) / masonry while a column masonry is masonry / repeat(3, 1fr) - the masonry's direction is completely implicit, never explicitly mentioned. Compare with display:masonry, which uses masonry: row repeat(3, 1fr) or masonry: column repeat(3, 1fr) (or in reverse order) - direction is clearly and explicitly provided via a keyword, and order of the values doesn't matter.

      Second, the "one string or multiple strings" problem with grid-template-areas infects this property too, and compounds. A row masonry is written "foo" 1fr "bar" 2fr "baz" 3fr / masonry (with this precisely fixed order of values), while a column masonry is written "foo bar baz" masonry / 1fr 2fr 3fr. This massive divergence in how you are required to write the property, depending solely on whether it's a row or column masonry, is completely unacceptable from a design standpoint. Nobody would ever design a property like this on purpose, it's terrible.

      Compare with display:masonry, which is masonry: row "foo bar baz" 1fr 2fr 3fr (with the three bits in any order), or masonry: column "foo bar baz" 1fr 2fr 3fr. Free re-ordering to whatever the author prefers, and the only difference between the two directions is the keyword declaring that direction.

  • the grid shorthand

    • In Grid, this combines the three properties of grid-template with the grid-auto-* properties - grid-auto-rows, grid-auto-columns, and grid-auto-flow. One would think that this inherits even more problems - all the grid-template issues + the grid-auto-flow problems, but actually the property doesn't work at all.

      That is, while you can of course still write a grid-template value in grid, it also offers this grammar for doing all both grid-template-* and grid-auto-*:

       <<'grid-template-rows'>> / [ auto-flow && dense? ] <<'grid-auto-columns'>>?
      

      (This specifies explicit rows and auto columns; there's also the reverse for auto rows and explicit columns.)

      This grammar is fundamentally incompatible with Masonry. It only lets you specify one of grid-template-rows/-columns, but Grid-masonry needs both so it can declare one axis with explicit tracks and the other as masonry. The most you could do is something like masonry / auto-flow 1fr: no explicit tracks listed at all, a meaningless auto-flow value (because Masonry is always auto-flowing), and a grid-auto-columns value that does get used, but only in a weird way: the grid will create enough implicit columns (with that size) to fit the largest spanning item or the furthest placed item. (Which means, in the common case, it'll just spawn a single implicit track.)

      With the Grid 3 values for grid-auto-flow it'll be possible to specify a slightly meaningful value instead of auto-flow, but it'll still mean you only have a single track in the common case. And, again, if you instead wanted to have a row masonry, you'd have to flip the order of things.

      (The grammar should be amended to allow specifying masonry on the auto-flow side, so the explicit track list is actually useful. But this is another indicator that the mental model underlying the Grid syntax is simply not designed for how Masonry wants to be written.)

      Also, the grid syntax only lets you choose between combining -rows/-columns with -areas, or with -auto-*. You can't actually shorthand all of the properties at the same time. (This isn't super intentional on Grid's part, fwiw. It would be completely reasonable to want to name your columns even if all your rows are auto-generated. The grammar just gets too complex to make that reasonable, so we left it out.)

      Compare all of this with display: masonry, which trivially lets you combine all the functionality in a single, fully-reorderable property with no complexity to deal with: masonry: column-reverse 1fr 2fr 3fr reverse;.

Conclusion

Even with a few more fixes to the grammar to make it work properly, Grid-masonry is still fundamentally awkward to specify and use. We would never design such a syntax from scratch; we'd be laughed out of the WG telcon. The cost of requiring authors to use such a clumsy syntax, and the precedent it establishes for how clumsy of a syntax we're willing to tolerate, is not remotely worth the benefits of authors not having to learn a new set of property names. As well, the benefit of reusing property names does not meaningfully carry over to actually reusing the property values in many cases; the actual meaning of those values is in several cases significantly distinct anyway, so authors are effectively still learning a new set of properties when using Grid-masonry, just spelled the same as an existing set.

This is actually a detriment to learning and understanding, versus having to learn a new-but-similar set of well-designed properties and values that match the underlying model better and much less clumsily.

Even if we designed Flexbox from scratch today, it would similarly not be able to reuse the Grid properties without being awkward and clumsy. I assert (without showing my work) that this would be true even if we designed the entire thing from scratch, all three of Flexbox, Grid, and Masonry together without any backwards compat to worry about. And the discussed possible future layout models, like "pillar", are similarly quite distinct and would have their own awkward/clumsy integration into such a combined layout mode.

In conclusion, Masonry should be its own display value, with its own set of properties that are well-designed for it. I suspect I (/Chrome) am willing to formally object to the current Grid-masonry design; it really is Just That Bad.

Compromise (that I don't like)

If the WG still disagrees with all of the above and thinks it is worth trying to reuse Grid properties in Masonry as much as possible, I offer this in-between proposal that avoids as much of the badness as I can.

I must stress that I do not like this proposal. A lot of the clumsiness is inherent to the fact that Grid is designed to be fully 2d, while Masonry is, similar to Flexbox, 1d-and-a-bit in its concepts. But it is substantially better than the current Grid-masonry proposal.

  • grid-template-rows/-columns/-areas reused as-is. Do not add the masonry keyword. (Ignore whichever one is in the masonry axis.)

    • Add the "intrinsic sizes in an auto-repeat function" grammar that Masonry allows. Either figure out some way to make that usable in Grid, or just give it fallback behavior (take one repetition), like when you use auto-repeats values in an instrincally-sized Grid today.
  • grid-auto-rows/-columns reused as-is. (Again, ignoring whichever one is in the masonry axis.)

  • grid-row/etc reused as-is. (Again, ignoring whichever one is in the masonry axis.)

  • Add a masonry-flow: none | [ row | column | row-reverse | column-reverse] || [ tie-start | tie-end ] property, which makes the Grid into a Masonry, and declares the masonry axis and direction, and tie-breaking direction. (Identical to masonry-flow in the current draft with an extra none keyword, except I'm changing the masonry-fill keywords. I want to make that change anyway.)

    (I'm using masonry-* naming here, to go along with the masonry-slack property we're already planning to add in either syntax. Alternately it could be grid-masonry if we want to nest it under the grid-* prefix.)

  • grid-auto-flow is ignored entirely; masonry-flow completely subsumes it.

  • Add a masonry shorthand, matching the current draft, which sets masonry-flow and all the existing grid-* properties appropriately.

  • Probably change the grid-template & grid shorthands to also reset masonry-flow. (masonry-slack can go either way; I'm inclined to leave it alone.)

This design lets us ignore the terrible syntax of grid-template-areas, grid-template, and grid (when used for Masonry) entirely; instead, authors will just use the masonry shorthand, which is simple and easy. masonry-flow makes the masonry axis clearer by reusing the already-understandable Flexbox syntax, and lets us avoid the clumsy reinterpretation of grid-auto-flow keywords entirely. If you really want to, tho, you can still use grid-template or grid as usual, and then set masonry-flow to activate the masonry axis. It does still carry some dead weight; authors have to be aware that several Grid properties are ignored when Masonry is active.

If we really wanted to minimize the number of new properties, we could instead merge masonry-flow into grid-auto-flow, as a separate grammar branch with a special keyword, like grid-auto-flow: masonry row, and have that be the trigger for Masonry behavior. Because this is a completely separate grammar branch, tho, it isn't meaningfully different from just having a separate property. Also, it really does do a substantially different thing than what grid-auto-flow does today, so merging it in isn't very helpful from a meaningfulness standpoint. I'd recommend against this.

Note that accepting this compromise does not imply that we'll continue to merge more layout modes into Grid just because they're 2d-ish. We'd still evaluate them as they come.

@fantasai
Copy link
Collaborator Author

Apple spent some time reviewing the TAG feedback and the comments above, and particularly considering the concerns about awkwardness with grid-auto-flow integration that Google also identified, and we have come up with the following counter-proposal building on the Just Use Grid option:

  1. Drop the masonry keyword from grid-template-*. Continue to use display: grid.
  2. Re-use the grid templating and grid placement properties, as currently.
  3. Unify grid-auto-flow with flex-flow as item-flow per the TAG’s feedback, and split it out into the following longhands as described in [css-flexbox][css-grid] Unifying grid-auto-flow and flex-flow #11480: item-direction, item-wrap, and item-pack. Also create item-slack, either as a longhand or separate. (Note: Open to renaming the item- prefix.)
  4. Add a collapse keyword to item-pack to trigger masonry-style layout.

The new flow controls for masonry would look like this:

item-flow: <item-direction> || <item-wrap> || <item-pack> || <item-slack>
shorthand for...
   item-direction: row | column | row-reverse | column-reverse
   item-wrap: wrap | wrap-reverse
   item-pack: normal | dense || collapse
   item-slack: <length-percentage>

Here’s the code to accomplish two use cases from this article:

grid-3-layout-light

.masonry {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  item-flow: collapse; /* == item-flow: row collapse 1em; */
  gap: 1rem; 
}

sideways-masonry-light

main {
  display: grid;
  grid-template-rows: 2fr 1fr;
  item-flow: column collapse; 
}

Thoughts?

@Crissov
Copy link
Contributor

Crissov commented Jan 11, 2025

item-tile-

@nathanchase
Copy link

nathanchase commented Jan 11, 2025

item-tile-

item is more aligned with current convention:

  • align-items
  • justify-items

The content inside of flexbox or grid are items.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants