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

Alternate masonry path forward #9041

Open
bfgeek opened this issue Jul 6, 2023 · 19 comments
Open

Alternate masonry path forward #9041

bfgeek opened this issue Jul 6, 2023 · 19 comments

Comments

@bfgeek
Copy link

bfgeek commented Jul 6, 2023

TL;DR

display: masonry;
masonry-template: repeat(auto-fill, auto);
masonry-direction: column-reverse;
masonry-span: 2;
masonry-threashold: 2px;

The primary issue with building masonry layout on top of grid is related to intrinsic-sizing (of the container itself, and intrinsic tracks).

Grid layout works by placing everything in the 2D grid, that is assigning each child a column(s), and row(s), then sizing the grid with all the children fixed within the grid (they can't jump to another grid position).

Masonry layout however works in reverse - by sizing the rows/columns first, then placing children in the "shortest" row/column. This means that we can't correctly size the rows/columns (as we don't know the content), and also can't size the container itself correctly (if sizing using min/max content sizes).

This is detailed in issue: #8206

There are potential workarounds to deal with this issue, e.g. assume that all children are in every row/column for the purposes of sizing, but this prevents some potentially desirable use cases.

One thing that seems desirable is to allow a wider/different syntax for rows/columns than is currently allowed for grid, e.g. masonry-template: repeat(auto-fill, auto).
(Above would measure all the masonry items, and select the best number of tracks to fit the content).
(Arguably above might be a better default than masonry-template: auto for example).
This isn't possible for grid-template for good reasons - but we could accept it for masonry.
One open question is if we need different track sizes or just one would suffice. All the designs I have personally seen have just one track repeated N times. Accepting just one track template would allow easier intrinsic sizing of spanners for example.

One addition which is currently missing with grid repeaters is the ability to clamp to a minimum / maximum number. This is more relevant with masonry. E.g. masonry-template: repeat(auto-fill, /* min */ 1, /* max */ 5, auto) would allow clamping to a maximum of 5 tracks which seems desirable from designs I've seen.
(this is probably a bad syntax but you get the idea).

Another missing in the current proposal is controlling the direction of the masonry flow. E.g. there are cases where you'd want the masonry axis to start from the block-end / inline-end.
This could be covered by a property similar to flex-direction , a simple (and likely understandable property) might be:
masonry-direction: row | row-reverse | column | column-reverse
(this would be similar to the originTop/originLeft controls in masonry.js https://masonry.desandro.com/options.html#originleft )

One issue with masonry style layouts is that things can easily be visually out of order, e.g. if the current tracks are [100px, 99px] the next masonry item would be placed in the 2nd track, when the first would be more natural. A potentially solution to this is some user defined "threshold" to "place within the first track within Xpx of the smallest track"
masonry-threshold: <length>

Things that aren't in this proposal vs. the current draft are:

Ian

@bfgeek bfgeek added the css-grid-3 Masonry Layout label Jul 6, 2023
@SebastianZ
Copy link
Contributor

Separating masonry from grid layout was already discussed in #4650 and had a bunch of proponents, including me.
@argyleink, @meyerweb, @AmeliaBR, @rachelandrew, @JoshuaLindquist, @thomascallahan FYI

As indicated by the different properties @bfgeek introduces, masonry layout works differently than grid in several points. And separating its syntax from grid also allows adding features that only apply to it and not to grid and vice versa.

Sebastian

@tabatkins tabatkins added this to Thursday in Cupertino F2F Agenda Jul 17, 2023
@rachelandrew
Copy link
Contributor

I've never been a fan of including masonry in grid layout. Mostly because we'd forever more be having to figure out how new grid stuff works with Masonry layout, which will always be a bit weird because a masonry layout is different to a grid layout.

The current spec makes masonry layouts do a whole bunch of extra things that I've not seen authors ask for, mostly because "why not?" once it's all bundled into grid. Without compelling use cases for these features, it feels as if we'd be adding future problems of needing to work round masonry for grid additions, plus making to harder to add masonry specific things.

I think this proposal achieves the things people want out of masonry, and avoids these pitfalls.

@fantasai
Copy link
Collaborator

(Fwiw I could have sworn we had a resolution to adopt column-reverse and row-reverse values for grid-auto-flow, but I can't find it.)

@Que-tin
Copy link

Que-tin commented Jul 20, 2023

(Fwiw I could have sworn we had a resolution to adopt column-reverse and row-reverse values for grid-auto-flow, but I can't find it.)

I was actually searching for this quite a lot lately and didn't find a resolution on this and to be honest not even a draft. Would that be smth. for the Cupertino F2F Agenda as well @fantasai?

@astearns astearns moved this from Thursday to Unslotted in Cupertino F2F Agenda Jul 20, 2023
@bfgeek
Copy link
Author

bfgeek commented Jul 20, 2023

So I don't forget - default alignment needs to be different for masonry as well. E.g. its desirable for replaced elements to stretch (vs. the grid default of start) similar to flexbox.

@bfgeek
Copy link
Author

bfgeek commented Sep 7, 2023

Another thing so I don't forget - variable track sizes is problematic with items that span multiple tracks with "dense" packing. To correctly place the item in the correct tracks, you need O(N) layout passes on the item.

@fantasai
Copy link
Collaborator

fantasai commented Sep 7, 2023

Breaking the specifics out into separate issues (not that this invalidates this one, or that listing them all here isn't useful, but still should have them filed individually):

@SebastianZ
Copy link
Contributor

SebastianZ commented Sep 7, 2023

  • No ability to place a masonry item in an explicit row/column. I personally haven't seen people do this. Personally I don't think it's needed, and somewhat harmful accessibility wise.

For what it's worth, I do have a use case for that at https://www.gamestar.de. That page has two columns. And those columns contain different sections, which are placed explicitly in those columns. In horizontal direction the sections are meant to align on tracks while vertically they should be independent from each other. At the same time, they are explicitly placed in one of the tracks.

Homepage layout at gamestar.de

The two-column split is just one example. There are other pages which use three or even four columns.

So, this seems to be a perfect match for masonry layout.

And I believe, basically every website that is split into several columns could benefit from masonry layout.
Take MDN for example.
Instead of using Grid, its three-column layout could be done using masonry, i.e.

display: masonry;
masonry-template: minmax(0,1fr) minmax(0,2.5fr) minmax(0,15rem);

The point of using Masonry here is that the height of the items should not depend on each other nor on a grid.

So, I'd vote for a masonry-track property that allows to place items explicitly in a track (or even span over multiple ones) similar to how grid-column and grid-row work.

Sebastian

@tabatkins
Copy link
Member

That's not really masonry tho, right? They're not selecting the column based on available space; the stuff in the first column is meant for the first column, the stuff in the second is meant for the second.

Today this would just be a grid with two columns and one row, with all the stuff in each column wrapped in a container. To fix the general problem of wanting to flow a mixed set of contents into a single grid cell without having to pre-wrap them in a container div we have #9098

@SebastianZ
Copy link
Contributor

They're not selecting the column based on available space; the stuff in the first column is meant for the first column, the stuff in the second is meant for the second.

Right. That use case avoids the auto-placement algorithm altogether, like it can be done in Grid and Flexbox, already. The benefit over Grid is that they are only aligned on one axis and the benefit over Flexbox is that they don't rely on wrapping logic.

Today this would just be a grid with two columns and one row, with all the stuff in each column wrapped in a container.

Correct. That's how it's solved right now in the first example.

To fix the general problem of wanting to flow a mixed set of contents into a single grid cell without having to pre-wrap them in a container div we have #9098

Yes, that issues would also solve that use case. Though that use case seems to be a natural fit for masonry and less so for grid.

Sebastian

@tabatkins
Copy link
Member

What I mean is, since there is no column auto-selection at all, this isn't Masonry. Masonry's entire reason for existing is to allow you to place items according to the tracks' current fill height; if you're skipping that entirely, then Masonry might not be the right abstraction for this. This is especially true if reusing Masonry as the layout abstraction for this (and making changes to accommodate it) would harm more core use-cases.

On the other hand, nothing about this case is particularly unusual for Grid. New functionality is needed (flowing multiple items into one cell as if they were grouped into a container element), but it's immediately compatible with the rest of Grid, too; it doesn't force us to reshape anything else about grid to accommodate it. As far as Grid is concerned it's exactly like just having a container element filled with stuff, and that's exactly what the use-case needs and wants out of it.

So yes, in theory we could address some variations of this "flow multiple items into one grid cell" use-case with Masonry, but we can't hit all of them, and even for the ones we can do, it requires adding additional features to Masonry that harm the core use-cases.

@SebastianZ
Copy link
Contributor

Masonry's entire reason for existing is to allow you to place items according to the tracks' current fill height

I'd argue that this is not true. The spec's introduction says this:

This module defines a layout system that removes that restriction so that items can be placed into Grid-like tracks in just one of the axes, while stacking them one after another in the other axis.

This is the main use case for Masonry. The auto-placement algorithm is one aspect of it, like it is for Grid layout.
And restricting it to auto-placement seems arbitrary to me and is also hugely restricting its usefulness. Allowing to place items manually (in addition to auto-placement) opens Masonry up to a whole new class of use cases.
The use case is not "flow multiple items into one grid cell". (That's handily expressed so that it fits to #9098.) The use case is "have multiple tracks in one axis and stack items in the other axis".

Sebastian

@tabatkins
Copy link
Member

Yes, that's an introduction for Grid Level 3. It was written starting from the assumption that this new functionality would be based on Grid, so it being somewhat Grid-biased is not a surprise.

But the use-case in the wild, that we are attempting to capture in a layout mode, is pretty clear: it's items of arbitrary size being placed relatively tightly into tracks according to whichever track is currently least-filled. Placing items into specific tracks without automatic placement has not been traditionally called "masonry" or addressed by those tools; it's instead been handled by "group them in a container element".

Anything going beyond that remit might be appropriate to solve with Masonry, or might be best solved with another layout mode (one that already exists or one not yet written!). We should not assume that every nearby use-case is necessarily appropriate to fold in, particularly when, as I said, doing so would harm the core use-cases. (Which allowing different-sized columns might do, as has been argued, by making some features (spanners, in particular) either not work correctly or be surprisingly expensive to layout.)

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Alternate masonry path forward.

The full IRC log of that discussion <TabAtkins> iank_: When Masonry was introduced there was discussion about whether this should be a new display type, or built into grid
<TabAtkins> iank_: After reviewing this in more detail, I'm more convinced we want a new display type
<TabAtkins> iank_: We didn't have a great proposal for what this would look like, so I typed up some details in a quick issue
<TabAtkins> iank_: There's some fudnamental tensions between Masonry layout and Grid. This leads to some undesireable complexities, possibly perf problems
<TabAtkins> iank_: So for a new masonry display type, we can do masonry-first, rather than bolting it onto Grid
<TabAtkins> iank_: This is so far a very simple proposal, it can be extended in the future, but it concentrates on the core use-cases
<TabAtkins> iank_: Handful of props. masonry-template tells how your non-masonry'd tracks look
<TabAtkins> iank_: One detail is that, at least for now, ahving all your tracks the same size is important for perf.
<TabAtkins> iank_: We also ahven't seen different-size tracks in the wild.
<TabAtkins> iank_: Another is masonry-direction, same concept as flex.
<TabAtkins> iank_: There are example where you want your masonry items to flow upwards
<TabAtkins> iank_: Another detail - you can tell a masonry item to span, but not specify in a specific track. Again, based on use-cases we haven't found any use for that.
<TabAtkins> iank_: A few other bits about alignment, squaring off.
<fantasai> scribe+
<TabAtkins> Rossen_: Next steps?
<TabAtkins> iank_: We might be interestsed in prototyping this in Chromium. I think if there are any fundamental issues, or use-cases that aren't covered by this proposal, that would be good to hear about
<TabAtkins> Rossen_: I see the issue thread is already fairly active, some +1s, some open issues.
<TabAtkins> Rossen_: I propose we take the convo back to the issue. When we have enough of an understanding on next steps we can bring them here.
<fantasai> -> https://github.com//issues/9041#issuecomment-1710838816
<TabAtkins> fantasai: I took Ian's issues and split them out into sub-issues
<Rossen_> ack fantasai
<TabAtkins> fantasai: I think we should go thru and address these individually
<TabAtkins> fantasai: The q of whether to make this a new display type or part of grid is kinda like the top of this issue, but some of the questions are "well is it even possible to build this into grid?" and I think we should answer that first
<TabAtkins> fantasai: Then the question about a new display type isn't about whether or not it's possible, but whether it's *better* to be part of Grid or a separate display type.
<TabAtkins> fantasai: I think all the issues Ian raises are addressable within the Grid framework, so it would be good to go thru the individual issues to see if they're actually blockers.
<TabAtkins> fantasai: Then we can come back and see whether there's acutally a blocker that forces a new display type, or if it *is* possible in Grid so it'll be more a decision of which is better
<plinss> q+
<TabAtkins> iank_: One thing I want to ensure is that, while lots of things are possible, perf is important. I'm concerned about quadratic behavior to add this into Grid.
<Rossen_> ack plinss
<TabAtkins> plinss: Orthogonal q - what's the status of layout worklets?
<TabAtkins> iank_: We have a prototype; we want to clean it up after our layout rearchitecture.
<TabAtkins> iank_: It's not a huge list of issues, we're just evaluating where it is on priority.
<TabAtkins> plinss: k, just curious. if we're experimenting with new display types, seems like a great opportunity to explore in userland
<TabAtkins> (fwiw I'm fairly certain Masonry *can* be done in the existing layout worklet API)

@nicoburns
Copy link

Regarding masonry-direction: I'd like to propose that this is generalised to box-direction and becomes a shared property that works for both Flexbox and Masonry layout (similar to how grid-gap became gap when support was expanded to Flexbox containers)

@stof
Copy link

stof commented Oct 25, 2023

grid-gpa having been generalized as gap for usage in flexbox actually made it impossible to detect support for gap in flexbox with @supports (as the gap property was already supported by browsers implementing Grid with the new property name). So is it a good idea to generalize like that ?

@nicoburns
Copy link

grid-gap having been generalized as gap for usage in flexbox actually made it impossible to detect support for gap in flexbox with @supports (as the gap property was already supported by browsers implementing Grid with the new property name). So is it a good idea to generalize like that ?

Hmm... I think that would be less likely to be a problem here if this was included in the first version the masonry spec as you would be able to just test for masonry support at all. In general, I would prefer properties to be combined like this. Otherwise you end up with lots of duplicates which is much harder for authors to remember. Imagine if margin, padding, aspect-ratio, etc all had separate variants for each layout mode.

@stof
Copy link

stof commented Oct 25, 2023

@nicoburns the issue is not about detecting support for it in Masonry, where the support should be detected for Masonry itself indeed. The issue would be detecting the support in Flexbox, in case box-direction gets implemented by a browser implementing Masonry without adding support for it in Flexbox (leaving no way to detect the missing support of Flexbox with box-direction).

Properties shared between multiple layouts would require these rules to be feature detectable properly:

  • the browser release that adds support for a property must add support for this property in all existing layouts supported by the browser, to avoid situations of partial support that cannot be detected
  • when adding a new property that is meant to affect multiple layouts, this should be specified for all of them when introducing the new property (otherwise the previous point become impossible to satisfy by browser vendors without a time-machine to change older versions that introduced the support...)

However, I have no idea how realistic enforcing those is.

margin and padding were there before the introduction of the various layout modes (at least the ones that came at a time where compatibility with @supports makes sense), so supporting them was part of the initial spec of those layouts.
And aspect-ratio was specified taking into account its impact on all layout modes, allowing to follow the rules above.

@nicoburns
Copy link

in case box-direction gets implemented by a browser implementing Masonry without adding support for it in Flexbox (leaving no way to detect the missing support of Flexbox with box-direction).

I mean, ideally this just wouldn't happen, and the release of the property could be coordinated for all layout modes (similarly to aspect-ratio). But in this case, I don't think it would matter too much if that didn't happen:

The issue would be detecting the support in Flexbox, in case box-direction gets implemented by a browser implementing Masonry without adding support for it in Flexbox (leaving no way to detect the missing support of Flexbox with box-direction).

What would be the use case for this? If you want to support older browsers that don't support box-direction with flexbox then you would need to set both box-direction and flex-direction. And there would be no point in doing this conditionally which would just add more code to do the same thing (as CSS will ignore properties it doesn't understand anyway).

If there were properties that did require layout-mode specific feature detection then I guess it might make sense to add the ability to specify display mode to @supports somehow.

@astearns astearns added this to Unsorted assorted in Feb 2024 Agenda Jan 30, 2024
@astearns astearns removed this from Unsorted assorted in Feb 2024 Agenda Feb 8, 2024
@astearns astearns added this to unsorted FTF in Feb 2024 Agenda Feb 11, 2024
@astearns astearns removed this from unsorted FTF in Feb 2024 Agenda Feb 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Development

No branches or pull requests

10 participants