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

Alternative masonry path forward #9041

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

Alternative masonry path forward #9041

bfgeek opened this issue Jul 6, 2023 · 132 comments
Labels

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

@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?

@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-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 ?

@nickautomatic
Copy link

nickautomatic commented Sep 26, 2024

I also have a strong preference for display: masonry over adding this functionality to CSS Grid, because:

  • Adding masonry to CSS Grid would make it signficantly harder to learn and understand. At the moment I think contrasting Grid with Flexbox can be a useful way of developing a mental model of what problems they each solve. But masonry has Flexbox-y aspects (it's not entirely unlike a wrapping flex layout), and the defining feature of grid is the ability to control layout in two dimensions, which you partially give up in a masonry-type layout. Given that, adding masonry to grid would make it harder to clearly articulate the difference between Flexbox and Grid
  • I'm not convinced masonry layouts really are a type of grid: if you're having to effectively disregard one of the grid dimensions then my feeling is that this is fundamentally not the same type of layout, even if it has similarities
  • The proposed syntax for display: masonry seems generally simpler, so would probably be preferable even in the absence of these other considerations.

(I realise I'm mostly echoing things other people have already said, so apologies if a simple "+1" would have been better! 😄)

@Wilto
Copy link

Wilto commented Sep 26, 2024

Strongly in favor of display: masonry.

@rjgotten
Copy link

@nickautomatic
masonry has Flexbox-y aspects (it's not entirely unlike a wrapping flex layout), and the defining feature of grid is the ability to control layout in two dimensions, which you partially give up in a masonry-type layout.

That's the thing. Conceptually masonry does flow like flex layout. It only shares some of its concepts with grid layout and column layout. Namely it shares with grid how you have control over the sizing of the tracks on the cross-axis, and it shares with column layout the auto-magical balancing of the contents over those cross-axis tracks.

But the predominant part of its characteristics is more like flex than grid from a conceptual point of view.
It's just that from an implementation point of view (in engines) it appears to have major commonalities with grid layout mechanics.

@robinetmiller
Copy link

FWIW from a rando dev: After reading Rachel Andrew's argument, I too am strongly in favour of display: masonry.

IMHO, the Safari team's argument that it's grid with an exception on one axis undervalues how confusing exceptions are for learning and comprehension (citation: spelling and grammar in the entirety of the English language).

Another small benefit of display: masonry is the conceptual rhyming with inline-block.

When you need some of the behaviour of inline, and some of the behaviour of block, there's a midpoint available. As several others have pointed out, masonry is a bit like grid and a bit like flex:

Flex: Control 1 dimension, fill 1 dimension
Masonry: Control 1 dimension, fill 2 dimensions
Grid: Control 2 dimensions, fill 2 dimensions

@nmn
Copy link

nmn commented Sep 26, 2024

There are many good reasons to choose both approaches, but I just want to push back against this notion that masonry is not a grid or that it is more like FlexBox. This simply isn't true. If you've decided to create mental model where you think of masonry like FlexBox, there is likely a misunderstanding. I believe people are thinking of how flex-wrap or inline or inline-block or even columns creates multiple "tracks" of content.

Even if that is true, it's important to not associate masonry with flexbox, it's simply many rows or columns of items that are aligned across one axis but not the other. There is a reason that masonry has been implemented with columns in the past, but not flexbox. Thinking of it another way, masonry is exactly like a grid but where alignment along one axis is thrown away and "packed".

These are all mental models that might help you personally, but FlexBox is, at its core, about distribution of space among the children proportionately. FlexBox doesn't even wrap by default. Masonry doesn't have any qualities of FlexBox and the only similarity being mentioned is the fact that it feels similar to wrapping. Even that is a misleading way to think about masonry.

Masonry items are places much like grid, except each item is placed as high as possible to "pack" it and alignment within a row is ignored.


Again, this is not an argument in favour of either API approach.


Personally, my own new personal model for thinking about masonry now is something along the lines of:

masonry : grid :: grid :: subgrid

Just like subgrid adds additional alignment constraints to a grid layout, grid layout adds additional alignment constraints to masonry.

So perhaps, display: masonry makes sense, but it should still have a strong connection to grid layout and share other properties that work the same across the two layout modes.

@Loirooriol
Copy link
Contributor

There is a reason that masonry has been implemented with columns in the past, but not flexbox.

@nmn I have literally implemented masonry (with masonry-slack: infinite) using flexbox: https://stackoverflow.com/a/35097136

@tabatkins
Copy link
Member

For me, reversing the vertical axis was exactly the role of row-reverse.

Note that the proposed behavior makes masonry-direction and flex-direction work in the same ways. A column-reverse Flexbox has columns that fill in reverse (bottom to top) order; a column-reverse Masonry has columns that fill in reverse (bottom to top) order. In many ways, Masonry is halfway between a Grid and a Flexbox, and the syntax in the "grid-independent" option splits that difference.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Alternative masonry path forward.

The full IRC log of that discussion <khush> rachelandrew summarize the feedback. we've got 2 versions in terms of feature parity they are the same
<khush> the syntax is different
<khush> taken it to 2 devs
<khush> after the initial post from webkit, we got feedback
<khush> there's no way that devs will get all features showed in the post if we go with separate syntax
<khush> went through all the comments and looked at how many of them said display:grid because that's the only way to get features
<fantasai> I think that's not quite correct, just that the state of the opposite proposal was to intentionally exclude some of the grid-integrated features.
<fantasai> at the time of that post
<khush> other feeedback is, is masonry grid or not.
<khush> as a teacher of CSS it matters how people think
<khush> there is noo consensus there
<khush> the other response, which approach is easier to teach and understand
<khush> that's the core issue, what is easier for devs to understand
<khush> that post is really hard to write
<khush> because it's complicated. display masonry has much simpler syntax. display grid requires changing other values
<khush> it's just hard. i'll have a hard time explaining it to people
<khush> the response to the second post has supported masonry
<khush> me and chrome team prefer display: masonry for ergonomics
<khush> the other point is future proofing
<khush> there are enough things in display grid which are weird
<khush> we will have to work around by saying they only work in masonry
<oriol> +1 to display:masonry
<astearns> ack fantasai
<khush> fantasai: i intentionally did not add it to the agenda. too early for this debate
<khush> underlying layout model is the same
<TabAtkins> q+
<khush> only syntax is up for debate
<khush> we only published it end of last week
<TabAtkins> (it's not just a syntax issue, there is still some behavior differences)
<khush> chrome madde the blog post last thursday
<TabAtkins> (and they're unresolvable imo)
<khush> we should continue to work on issues
<khush> impl is not blocked
<khush> i want to collect author feedback and think through the syntax
<khush> get input from TAG
<khush> too soon to start debating syntax
<khush> Won't go into my opinion on the syntax
<khush> the state of the draft which outlines the 2 syntax and have same functionality
<khush> there's pros/cons to each syntax. one is definitely not better
<khush> has to come from the context where the syntax is being used and rest of CSS
<khush> let's not argue it here right now
<astearns> ack TabAtkins
<khush> TabAtkins: the difference between integration into grid vs masonry is not just syntax.
<khush> diff initial values for properties
<khush> display: masonry gets you better values right away
<khush> masonry can do auto repeat of instrinsic size tracks
<khush> that is not even possible with grid
<khush> fantasai: those are separate issues
<khush> TabAtkins : it's incorrect to say it's only syntax. behaviour is different
<khush> i'm fine with deferring
<khush> TabAtkins: it's pretty clear that a bunch of common cases are indeed simpler with the display: masonry syntax.
<khush> want to see similar examples with grid.
<rachelandrew> Chrome post https://developer.chrome.com/blog/masonry-syntax
<khush> let's have those examples when this discussion happens
<keithamus> q+
<khush> keithamus: display: masonry is a inside display: grid
<khush> i can't see any examples for inline masonry
<khush> TabAtkins assume inline-masonry exists.
<khush> astearns please file an issue for this
<khush> fantasai: one argument for grid syntax is we don't have props which only apply to specific context
<khush> it's better to go with more examples/input before debating
<TabAtkins> I think we actually don't have *any* such properties here. Every property is *at least slightly* different in its syntax.

@bbag
Copy link

bbag commented Sep 27, 2024

Throwing in a +1 for display: masonry.

For me, the term "grid" implies consistent tracks along two axes, and everything is aligned along those tracks. In other words, in my mind, a "grid" has horizontal and vertical lines (the grid tracks) that all extend to cover the grid's area. All rows and columns are consistent across the whole grid.

A masonry layout may share a lot of similar layout properties as a grid, and the discussion around all this is legitimately great, but in my mind it is distinctly not a grid. The tracks along one axis do not necessarily extend the full length of that axis, and it does not fit the common definition of what a "grid" is.

Apart from what others have pointed out, like how defining it separately as display: masonry allows it to evolve independently of display: grid, to me it's simply more confusing to fit it into display: grid than it is to explicitly break it out as display: masonry.

Either way though, I'll just be happy masonry is finally making it to CSS. 🙂

@cat394
Copy link

cat394 commented Sep 27, 2024

@nmn

I am not trying to persuade you, nor am I denying your opinion.

However, I have created an image that illustrates the differences between the two structures I have in mind for creating a masonry layout. I hope you find it helpful.

First, for developers familiar with grid layouts, masonry layouts may seem somewhat complex. The image of items being placed along the horizontal axis in a grid may lead to the impression that the axis specified for masonry disappears, and items that were placed below rise to fill the gaps.

IMG_0159

The masonry keyword can be viewed as an automatic packing feature within the grid system, and treating it as part of the grid API does not create any contradiction. However, imagining all items rising up within the grid can be challenging, and the linear layout lines that a grid typically provides may be disrupted, making the design harder to manage.

On the other hand, if we treat the masonry layout as an entirely separate layout, it’s easier to picture each item simply aligning along the main axis in its respective track. I found this easier to understand, and the result of a masonry layout becomes much more predictable in my opinion.

IMG_0160

Of course, the way people perceive flex, grid, or masonry layouts may differ from person to person, and if you find the grid syntax intuitive, that’s something that shouldn’t be dismissed.

As you mentioned, the design outcomes for both grid and masonry layouts are indeed similar. Unifying these interfaces will allow us to work with the same mental model, avoiding future divergence between the APIs, which I think is a good thing.

The reason I support display: masonry; instead of grid syntax is rooted in this understanding. I hope this explanation helps you see where I’m coming from.

Lastly, if my understanding or images are incorrect, please feel free to point it out.

@maria-gourevitch
Copy link

Like many commenters above, I find display: masonry to have clearer ergonomics (a grid-based design, to me, has underlying rows and columns). In addition, display: masonry would make a progressive enhancement approach cleaner (imho) for designs where the preferred fallback is Flexbox (or anything other than Grid):

display: masonry, fall back to Flexbox

/*All of the rules for this class are in the same place*/
.masonry {
   display: flex;
   flex-wrap: wrap;
  /*The following lines will be ignored by browsers that don't understand masonry 
   and applied by browsers that understand masonry, overriding the previous lines*/
   display: masonry;
   masonry-template: repeat(auto-fill, auto);
}

masonry as part of Grid, fall back to Flexbox

/*Rules for the class are split across different layers/queries,
resulting in bulkier CSS and making it less efficient to update*/

/*Media queries do not increase specificity, 
so make sure fallbacks are deprioritized*/
@layer fallbacks { 
   .masonry {
      display: flex;
      flex-wrap: wrap;
   }
}

@supports (grid-template-rows: masonry) {
  .masonry {
      display: grid;
      grid-template-rows: masonry;
  }
}

@nmn
Copy link

nmn commented Sep 29, 2024

@cat394 Thank you for your explanation and your art makes a lot of sense! And just to further clarify my last comment, I completely understand not thinking of masonry as a grid but as a new type of layout. I was specifically warning against thinking about it like Flexbox too much. (@Loirooriol you essentially used "wrapping" to make masonry and not really the core feature of flexbox, which is to "flex" the children to grow or shrink, which was my entire point. But also, thanks for the great solution!)

If the design of the proposal doesn't change, I think your argument holds up very well. I'm however unsure if we've landed on the right approach for masonry. This talk from Nicole Sullivan really brought up a lot of questions for me.

https://www.youtube.com/watch?v=3h6BCTgQ4yw

  1. As @cat394 mentioned, masonry doesn't just "float items up". Rather, the order of the items can change altogether. This is often an undesirable behaviour and for a clean tab-index order it's often best to minimize the amount of re-ordering that takes place and to maintain the left to right order of children when possible.

  2. I also think it's very useful to be able to define *-columns: 1fr min-content to be able to make the layout useful

  3. I also found the idea of mixing grid and masonry intriguing. I think it's worth considering layouts where certain columns ignore the row tracks and pack the children within them, but not others. Neither API proposal would currently support this.


Traditionally, masonry on the web has been kind of pigeonholed into few use-cases. This is primarily because it wasn't a native CSS feature. When adding a new CSS layout, let's be careful about the widest possible number of use-cases.

@rjgotten
Copy link

rjgotten commented Sep 30, 2024

@nmn
I also found the idea of mixing grid and masonry intriguing. I think it's worth considering layouts where certain columns ignore the row tracks and pack the children within them, but not others. Neither API proposal would currently support this.

That would be a 'masonry inside grid' scenario, with masonry-template-tracks: subgrid to inherit the column tracks from the parent grid, I'd think. That is --assuming masonry would get subgrid support to be able to use tracks from a parent grid. At that point it should probably be renamed sub with subgrid becoming a legacy alias; similar to e.g. grid-gap having become gap, etc.

It'd actually be banger if treating those as separate layout models would force subgrid track sharing to be done in a way that opens it up to other layout mechanisms as well. ( :: cough :: columns: subgrid :: cough :: )

@nmn
Copy link

nmn commented Oct 1, 2024

@rjgotten not quite because that would require a container for that "grid within masonry" or vice versa.

Here's a contrived example of what I'm describing:

Screenshot 2024-09-30 at 10 25 33 pm

It's a grid layout, except the last column ignores the row alignment and "floats" all items within it upwards and packs them. On smaller screens, the last column goes away and the elements within it become part of the grid like normal.

AFAIK, this is not possible with either proposal. I'm also not sure it's a good use-case to try and solve. I just found the suggestion intriguing. Is this a desirable layout solution?

@firefoxic
Copy link
Contributor

I'm also not sure it's a good use-case to try and solve.

I'm not sure about that either 🤭

@rjgotten
Copy link

rjgotten commented Oct 1, 2024

@nmn
AFAIK, this is not possible with either proposal.

If subgrid would be generalized across grid, masonry and other layouts capable of using tracks, then it's possible.
You do need the nested containing element which forms the 'sub' that uses masonry - and then in the scenario you describe where:

On smaller screens, the last column goes away and the elements within it become part of the grid like normal.

you simply mark that container as display:contents and its children become grid children instead ...

Also - the exact layout you're describing is already possible today:
It's just a grid with a flex box in column direction set in the last column, spanning from row 1 to row -1.

@nmn
Copy link

nmn commented Oct 2, 2024

@rjgotten You're missing the point that all the children are direct children in a single container. Of course that layout is possible by using additional containers for the sidebar, and then using media queries to detect when it goes away and conditional using display: contents and then using order to move them between the grid elements. However, this would still break tab order.

But again, as I said, this is a contrived example, so it feels extra dumb. But I think there is a chance this capability is useful and may enable other layouts that are actually desirable.

@tabatkins
Copy link
Member

@nmn

This talk from Nicole Sullivan really brought up a lot of questions for me.

That talk is out-of-date on the state of the proposals; similar to the Apple blog post at the top of this issue thread, it states that some things are impossible in one syntax when that is no longer true. (Basically anything written more than a few weeks ago is now useless for the purpose of this conversation and should probably be ignored.) Both syntaxes are capable of expressing the same things; it's a question of what defaults are best, how easy it is to express things, how teachable it is, etc.

Also, and somewhat more importantly, the syntax has never been the reason that one proposal or another had or lacked a particular ability. Chrome had an objection to the functionality of the original Apple proposal, based on the way it was described to work; the syntax used for it was irrelevant. (The Chrome proposal's earlier syntax was more restrictive, so that things with bad performance couldn't be written; it was the perf that was the issue, not how it was written). We've since figured out a great compromise that allows the flexibility that the Apple proposal wanted, and the perf characteristics that the Chrome proposal tried to maintain.

@nmn
Copy link

nmn commented Oct 2, 2024

@tabatkins

First, let me defend Nicole's talk. It wasn't biased in the same way the webkit blog post was. It didn't favour either API proposal and intentionally tried to stray away from the topic entirely. It mostly presented the cool stuff that might be coming to CSS and asked for feedback. She also presented a few pieces of feedback she had received from various devs. None of these pieces of feedback moved me in favour of either proposal. They were generally ideas about things that neither API support as written today.

And so I just came to add to that conversation, not take part in this heated debate about which API anymore. It's not important enough to me. Even if the proposal I like less gets standardised, I will still be happy about it.

And so...

  • In my last comment I didn't express any opinion on which API should be chosen.
  • I asked for the ability to have grid-row: span fit-content for grid layout. This is not relevant to the masonry proposal, but I mentioned it here, because I think it's loosely related.
  • I do think a "packed" layout with no "tracks" in either axis is something that is sometimes desirable. Imagine a word cloud, or an image cloud which creates a collage-like layout. I'm not sure if that belongs in masonry layout, but I figured it's useful to bring it up now in case it is.

I know this debate has gotten quite heated and maybe even a bit ugly, so I understand your reaction. But despite my earlier comments taking sides in the debate, I've moved on.

@xcrap
Copy link

xcrap commented Oct 3, 2024

👍 for display: masonry.

Do not mix concepts, a separate masonry it's the right way even it borrows some grid syntax.

@alkorlos
Copy link
Contributor

alkorlos commented Oct 4, 2024

Think display: masonry; would be clearer and more convenient for developers.

Based on what I see, the main argument in favor of masonry layout in grid a few months ago was the concern that a lot of functionality would be lost if display: masonry; were implemented. Now, there are examples showing that the functionality of a separate specification would not left one specification.

At the same time, the option of masonry layout in grid has many problems, which have been discussed above. The most important one for me — is that in a masonry layout in grid implementation, there would be many properties and values valid only for grid or only for masonry, and to avoid this kind of behavior would be good.

Сan't find Mozilla position on this issue. They created the first version of the masonry layout in grid specification and implemented it in an experimental browser version, but what do they think about the advantages and disadvantages of display: masonry;? It would be interesting to read their position.

@nmn
Copy link

nmn commented Oct 4, 2024

there would be many properties and values valid only for grid or only for masonry

I this repeated a lot but I don't see it summarised. All I know is that certain grid properties lose meaning in masonry.

  • grid-row: 1 doesn't make sense in masonry because there are no rows.

What else? What's a masonry-only property?

@tabatkins
Copy link
Member

Any two-dimensional value doesn't make sense in Masonry; it needs to be either re-interpreted as 1d or (perhaps partially) ignored.

  • grid-row (when you have a column masonry), and the corresponding grid-row-start and grid-row-end properties
  • grid-area using the 4-value syntax
  • grid-template-areas defining more than one row and column
  • grid-auto-rows (when you have a column masonry)
  • grid-auto-flow all currently values are useless (Masonry always auto-flows and doesn't do dense). The *-reverse keywords introduced in Grid 3 do make sense in Masonry, but one of them is useless depending on whether you have a row or column masonry. (And, as currently defined, the one that actually works is confusing: a column masonry uses row-reverse to break column ties from right to left, because a Grid would use row-reverse to indicate that its rows are filled from the right to left. But a column masonry doesn't have rows, it just fills its columns in a directly reminiscent of a Grid filling its rows.)
  • 'align-self' and 'align-items' (on a column masonry) do nothing (and that's correct and fine; they do nothing in display:masonry too)

As for Masonry-only:

  • masonry-slack determines when there are ties in masonry placement; it does nothing in Grid
  • using intrinsic size keywords in auto-repetitions when defining tracks (repeat(auto-fit, auto)) only works in Masonry

@nmn
Copy link

nmn commented Oct 5, 2024

Thanks @tabatkins!

This all makes sense. I do think that repeat(auto-fit, auto) support should be added to grid as well.

@rjgotten
Copy link

rjgotten commented Oct 7, 2024

@nmn
I do think that repeat(auto-fit, auto) support should be added to grid as well.

It's already been explained why that's not really viable performance-wise.

@Yusuf-KaYeht
Copy link

Im also definitely going with display: masonry;.
Even tho it would bring even more css declarations that might make it confusing to some people.
Like ``grid-template-rowstomasonry-template-tracks`

With display: grid; grid-template-rows: masonry; (or as I would prefer collapse as the keyword) is a lot simpler to remember for horizontal and vertical layouts (template-rows / template-columns).

But as long as we have the same capabilities and features with the “display: masonry” approach, and even save the developers implementing it some headaches and browser performance, I'm all for it.

@nmn
Copy link

nmn commented Oct 8, 2024

@rjgotten Yes, but I disagree with the proposed way it's supposed to work in grid. Anyway, that's a discussion for another time.

@ethanjv
Copy link

ethanjv commented Oct 15, 2024

Hi everyone! Last week I presented a breakout talk at BlinkOn 19 showcasing some of the unexpected behaviors that the current spec for masonry might surface for web developers (here's a link to the slides).

I believe the examples provided are good points to keep in mind while debating whether we should make masonry its own display type or not, since these behavioral differences will be surfaced in some of the more common scenarios.

@korenevskiy
Copy link

korenevskiy commented Oct 15, 2024

The choice between displaying grid:masonry and template-row: masonry is difficult. It's actually quite simple. It is necessary to understand the common problem of both approaches. The fact is that both approaches are not 100%. Let's combine both approaches.

  • One of the approaches is logical, but more complicated for simple writing.
  • At the same time, the other approach is simple to write, but a little bit not logical.

Let's take the best of both approaches
most people are bothered by the templatecolumn:masonry (Display:GRID) scheme, what needs to be written is row-reverse.
NO:

grid-auto-flow: row-reverse;

But we will write.
YES

grid-auto-flow: flow-reverse;

Now it will not be confusing that when specifying the direction of the columns we write lines, now we will just write a change in direction.

Let's take the best of both options.

or you can just write REVERSE
We can already see that this is a property of direction. Let's just write REVERSE in it
YES

grid-auto-flow: reverse;

You can also write an abbreviated version of the reverse .

.masonry {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: masonry / reverse;
}

There are no problems at all with the fact that you have to write 4 lines, an abbreviated version has always been present in the GRID display.

Can you please rate my suggestions????

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