-
Notifications
You must be signed in to change notification settings - Fork 661
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
Comments
Separating masonry from grid layout was already discussed in #4650 and had a bunch of proponents, including me. 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 |
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. |
(Fwiw I could have sworn we had a resolution to adopt |
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? |
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. |
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. |
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. 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. 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 Sebastian |
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 |
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.
Correct. That's how it's solved right now in the first example.
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 |
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. |
I'd argue that this is not true. The spec's introduction says this:
This is the main use case for Masonry. The auto-placement algorithm is one aspect of it, like it is for Grid layout. Sebastian |
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.) |
The CSS Working Group just discussed 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) |
Regarding |
grid-gap having been generalized as gap for usage in flexbox actually made it impossible to detect support for gap in flexbox with |
I also have a strong preference for
(I realise I'm mostly echoing things other people have already said, so apologies if a simple "+1" would have been better! 😄) |
Strongly in favor of |
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. |
FWIW from a rando dev: After reading Rachel Andrew's argument, I too am strongly in favour of 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 When you need some of the behaviour of Flex: Control 1 dimension, fill 1 dimension |
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 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:
Just like subgrid adds additional alignment constraints to a grid layout, grid layout adds additional alignment constraints to masonry. So perhaps, |
@nmn I have literally implemented masonry (with |
Note that the proposed behavior makes |
The CSS Working Group just discussed 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. |
Throwing in a +1 for 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 Either way though, I'll just be happy masonry is finally making it to CSS. 🙂 |
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. The 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. 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 Lastly, if my understanding or images are incorrect, please feel free to point it out. |
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
masonry as part of Grid, fall back to Flexbox
|
@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
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. |
That would be a 'masonry inside grid' scenario, with 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 :: |
@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: 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? |
I'm not sure about that either 🤭 |
If subgrid would be generalized across grid, masonry and other layouts capable of using tracks, then it's possible.
you simply mark that container as Also - the exact layout you're describing is already possible today: |
@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 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. |
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. |
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...
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. |
👍 for display: masonry. Do not mix concepts, a separate masonry it's the right way even it borrows some grid syntax. |
Think Based on what I see, the main argument in favor of At the same time, the option of Сan't find Mozilla position on this issue. They created the first version of the |
I this repeated a lot but I don't see it summarised. All I know is that certain grid properties lose meaning in masonry.
What else? What's a masonry-only property? |
Any two-dimensional value doesn't make sense in Masonry; it needs to be either re-interpreted as 1d or (perhaps partially) ignored.
As for Masonry-only:
|
Thanks @tabatkins! This all makes sense. I do think that |
It's already been explained why that's not really viable performance-wise. |
Im also definitely going with With 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. |
@rjgotten Yes, but I disagree with the proposed way it's supposed to work in grid. Anyway, that's a discussion for another time. |
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. |
The choice between displaying
Let's take the best of both approaches grid-auto-flow: row-reverse; But we will write. 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 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???? |
TL;DR
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
The text was updated successfully, but these errors were encountered: