w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.52k stars 673 forks source link

Alternative masonry path forward #9041

Open bfgeek opened 1 year ago

bfgeek commented 1 year ago

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: https://github.com/w3c/csswg-drafts/issues/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

xaddict commented 7 months ago

@chrisarmstrong

When I say background: black, then switch it to background: linear-gradient(45deg, black, white), it doesn't matter to me HOW the browser is implementing that instruction... I’m simply telling it what I want it to look like. If the browser has to switch to an entirely different rendering approach to implement that instruction in a performant way, that’s a problem for the browser dev, not the CSS dev.

With that example, you're actually advocating for display: masonry. You change the value to make it do something different (rendering a color vs rendering a gradient). I've adopted your paragraph and inserted grid and masonry into it:

When I say display: block, then switch it to display: none, or display: grid, or display: masonry, it doesn't matter to me HOW the browser is implementing that instruction... I'm simply telling it what I want it to look like. If the browser has to switch to entirely different rendering approach to implement that instruction in a performant way, that’s a problem for the browser dev, not the CSS dev.

xaddict commented 7 months ago

I just came here to +1 the display: masonry btw

phaux commented 6 months ago

I wouldn't mind splitting masonry and grid as long as they can inherit template rows/columns from each other like in the subgrid. It should work even when the display types are different: subgrid in masonry and submasonry in grid.

In the future, this inheriting capability could also be expanded to multiline flexbox.

mirisuzanne commented 6 months ago

I do wonder if there's any best-of-both approach here? But I don't know what that would look like. Just thinking: gap works in both flexbox and grid display values. Are there more properties that could be shared across grid and masonry displays? Or, as per @phaux, useful ways for the two layouts to relate to each other?

I get the complexity of properties working slightly different in different contexts, but it also feels real awkward having nearly-identical properties with nearly-identical syntax, but no interop. I'm not convinced that's actually "more clear" for authors in any meaningful way.

xaddict commented 6 months ago

I do wonder if there's any best-of-both approach here? But I don't know what that would look like. Just thinking: gap works in both flexbox and grid display values. Are there more properties that could be shared across grid and masonry displays? Or, as per @phaux, useful ways for the two layouts to relate to each other?

I get the complexity of properties working slightly different in different contexts, but it also feels real awkward having nearly-identical properties with nearly-identical syntax, but no interop. I'm not convinced that's actually "more clear" for authors in any meaningful way.

@mirisuzanne Rachel Andrew has done an excellent job (as they always do) writing down the reasoning and shareable properties: https://developer.chrome.com/blog/masonry

Plus, this write-up by Tab Atkins (one of the original spec writers for css grid) explains why "nearly-identical" is the best possible situation right now, whether masonry becomes an extension to css grid or its own layout: https://github.com/w3c/csswg-drafts/issues/9041#issuecomment-2075501616

Some more thoughts:

marcelhageman commented 6 months ago

I'm not entirely sure if this needs to be heard or not, but my take: Masonry isn't a grid. If you play city-building games, a grid is what's known as the American style of box-like structures. Masonry is not that.

It's a list of boxes, and they are flexible in both size and positioning: I would label it a "flex box" :)

What makes far more sense, to me, is a more grammatically sensible naming if we want to keep it in line with what CSS already has: flex and a way to align items, namely align-items. A new value would be to compact a flexible box layout.

Example:

.masonry {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: compact;
  gap: 1px;
}

You might even consider more specific options:

align-items: compact-start;

Which would push blocks upward into their available white space (excluding the gap);

align-items: compact-end;

Which would push blocks downward into their available white space (excluding the gap).

It would also work if your flexbox is in the column direction (compacting to the left or right).

Potential issues:

  1. In a row setup, what if one column in that row is wider? I'd say: that's up to the developer;
  2. What if one column is significantly taller than others? I'd say: magic rearranging of items should be left to JavaScript.

Please don't make it into a grid addition. I feel that a masonry layout is absolutely not a grid.

frivoal commented 6 months ago

Here's another way to look at the question: how often will it be true that a gird, set up with the same values for the applicable properties, will be a desirable fallback for a masonry design in browsers where masonry is not supported?

If people will need to change all sorts of things anyway, and need to rely on @supports for fallback, then having them be separate things can be a cost authors would reasonably be willing to bear, as they're setting them up differently anyway. On the other hand, if you have to say the same thing in two different sets of properties can be aggravating.

I think the theoretical answer is yes, grid can work as a fall back for masonry in many cases. But I'm more interested in author feedback based on real experience: you could fall back to an identically set up grid, but would you?

I suspect the answer might be: not if you want a good design, but if fallback is more of an afterthought, falling back to an identically set up grid is often good enough. I don't know how much this expectation matches author experience at large.

andrewCodes commented 6 months ago

This is definitely a preferable implementation to the one advocated by WebKit. However I really don't think this is a valuable use of anyone's time. There are so many defined things in CSS yet to be implemented across browsers not to mention significant inconsistency between browsers and browser bugs. Time and effort would be far better spent getting up to speed and collaborating more rather than trying to define and make something with relatively few applications all the while arguing over the best way to do it. This entire debate strikes me as a case of browser creators making what they want to make rather than what the web, users and developers actually need.

stubbornella commented 6 months ago

In other words, every example given in Jen's blog post is just fine. Those are all totally doable, no objections here. We just object to the possibility of writing, say, grid-template-columns: 50px auto 100px;, because in degenerate cases (which are more common than one would suppose), they cause quadratic or even exponential layout behavior.

@tabatkins can you give an example of a common degenerate case?

tabatkins commented 6 months ago

Any case where you have a large number of tracks and/or items. Authors do all sorts of weird stuff for all sorts of reasons; they write Grids that are far larger than we had any reason to believe they'd need, for example.

tabatkins commented 6 months ago

Hmmm, did I never post my alt document here? I shared it with Elika, but I can't immediately find any place I might have shared it with the rest of the group.

I had a sketch of a proposal at the end of my earlier comment, and I've gone ahead and written a first draft of an alternate spec for a full Masonry display type here: https://tabatkins.github.io/specs/css-masonry/

ydaniv commented 5 months ago

Reponding to @frivoal:

I suspect the answer might be: not if you want a good design, but if fallback is more of an afterthought, falling back to an identically set up grid is often good enough. I don't know how much this expectation matches author experience at large.

From my experience, in most cases, falling back from an intentional design of a masonry to a grid is not going to be acceptable. For example, in the cases I can account for, if a user asked for a masonry then they want that to be the layout, regardless of whether it will be done via CSS or not.

jcnevess commented 2 months ago

For me, display: masonry is clearer and enables masonry and grid to evolve separately.

suethepooh commented 2 months ago

+1 for display:masonry

tylersticka commented 2 months ago

I appreciate all the thought that's gone into this so far. I'd be delighted to use either proposed direction.

That said, I prefer display: masonry conceptually.

For context, in our client work we're sometimes called upon to implement masonry grids. We are often asked to embed in existing design and dev teams to help teach them modern web standards over the course of the project. In recent years, the two primary methods we've used to pull off masonry layouts are:

What I've personally observed is:

But again, either proposal would be simpler to use (and teach) than the hacks we currently resort to.

jimmyfrasche commented 2 months ago

I started off at display: grid then went to display: masonry but after the last article I'm back to display: grid. They're so close to the same it's almost more confusing to split them up because then I'll have to keep track of a bunch of subtle differences in syntax vs "it's just all grid".

JulienWilhelm commented 2 months ago

Grid works well for grid. And it is already complex enough for many.

I think it's better to use a specific syntax starting with display: masonry.

As mentioned here, the specification will be freer to evolve over time Also, this will make the CSS declarations more obvious to everyone.

cat394 commented 2 months ago

Hello everyone,

I would like to express my opinion that the masonry layout should be integrated as part of the grid layout, for the reasons outlined below.

Defining CASE 1 and CASE 2

In this discussion, I will refer to the case where display: masonry; is treated as a separate layout property as CASE 1, and the case where masonry is integrated as part of the grid layout as CASE 2. Throughout this explanation, I will compare these two approaches in terms of compatibility, benefits, fallback strategies, and developer experience.

Compatibility with Grid Layout

When considering masonry as part of the grid layout (as in CASE 2), some may worry about potential conflicts between the default properties of grid and those of masonry layouts. However, I believe that in most cases, these two types of layouts would not conflict with each other. Even when creating masonry layouts using grid, there is little need to override the default grid properties. For example, as demonstrated in this Webkit demo, typical masonry layouts can be created without the need for complicated CSS tricks or overriding grid properties. Additionally, a Chrome blog post comparing CASE 1 and CASE 2 shows that there is no significant difference in the amount of CSS required between the two approaches. While it is possible that future grid enhancements might introduce default property values that developers may want to set differently for masonry and grid layouts, at present, it is difficult to find concrete cases where such conflicts would arise.

Benefits of Treating the Masonry Layout as Part of the Grid Layout

One of the key benefits of integrating masonry into the grid layout (as in CASE 2) is the ability to leverage existing grid features, such as subgrids. Subgrids allow for cohesive designs among child elements within a grid, something highly desirable in many masonry layouts as well. Additionally, I believe that future enhancements to the grid layout will also be beneficial for masonry, making their integration even more valuable. By treating masonry as an extension of the grid layout, developers would be able to start using it immediately, without needing to learn a completely new system.

Fallback Strategy

In terms of fallback support, while it may seem like a disadvantage that CSS @supports won’t be applicable in CASE 2, I do not consider this a major issue. Masonry layouts involve items with varying sizes and aspect ratios, and attempting to replicate this using the current grid layout could result in large gaps or overflowing elements, which would lead to unpredictable designs. Until masonry is more broadly supported in browsers, using a JavaScript solution like Masonry.js would be a wise fallback choice.

Developer Experience

If masonry were implemented as a separate set of properties, similar to grid (as in CASE 1), developers would need to learn a substantial number of new CSS properties, which could lead to confusion. Learning even one new property can be challenging for developers, and increasing the number of new concepts makes this even more difficult. On the other hand, by making masonry part of the grid layout (as in CASE 2), developers would only need to understand the masonry keyword and could immediately apply their existing knowledge of grid properties. This would not only make the learning curve less steep, but it would also speed up adoption of masonry layouts in practical development. Furthermore, being able to directly use newly introduced grid properties within masonry layouts would reduce the need for developers to remember additional rules.

Conclusion

In conclusion, I believe that integrating masonry as part of the grid layout would provide a more intuitive and consistent developer experience. It would also ensure flexible and expressive designs, while benefiting from future grid enhancements. The fact that there is no significant difference in the CSS required between the two approaches, as shown in the Chrome blog, adds further support to this integration. For these reasons, I strongly advocate for adopting masonry as part of the grid layout.

rjgotten commented 2 months ago

Fallback Strategy

In terms of fallback support, while it may seem like a disadvantage that CSS @supports won’t be applicable in CASE 2, I do not consider this a major issue. Masonry layouts involve items with varying sizes and aspect ratios, and attempting to replicate this using the current grid layout could result in large gaps or overflowing elements, which would lead to unpredictable designs. Until masonry is more broadly supported in browsers, using a JavaScript solution like Masonry.js would be a wise fallback choice.

Using a layout that is entirely different and doesn't try to perform masonry would be another wise fallback choice. Much more wise than relying on a JavaScript library to patch things over, which has its own problems. (Runtime performance; download footprint; transparent upgrade to the real CSS masonry once a user agent starts supporting it; etc.)

The scenario presented is flawed, because it argues from the position that authors who are faced with a user agent that doesn't support masonry, would only bother to use @supports to implement fallbacks that try and use grid layout to get something that looks like a flawed masonry.

It dismisses the possibility that @supports-support could be used to switch into a different layout strategy entirely, rather than trying to shoehorn in something not-quite-masonry. And for such broad layout shift-overs, @support could be invaluable, indeed.

Benefits of Treating the Masonry Layout as Part of the Grid Layout

One of the key benefits of integrating masonry into the grid layout (as in CASE 2) is the ability to leverage existing grid features, such as subgrids. Subgrids allow for cohesive designs among child elements within a grid, something highly desirable in many masonry layouts as well.

This is a false dichotomy and should be dismissed as a benefit on that alone.

The syntax and semantics of the CSS that will drive masonry layout is a concern that is separate from the actual layout mechanics itself, which internally in implementation by user agents can still re-use parts of the existing mechanics for grids, including subgrids. For cases where masonry is nested inside grid, or grid inside masonry, the relationship between the two can be made explicit. And a syntax separate from the grid syntax can still incorporate a subgrid keyword to establish the parent-child relationship. Albeit, maybe that should be generalized to just be sub, where subgrid becomes an alias to sub.

Developer Experience

If masonry were implemented as a separate set of properties, similar to grid (as in CASE 1), developers would need to learn a substantial number of new CSS properties, which could lead to confusion. Learning even one new property can be challenging for developers, and increasing the number of new concepts makes this even more difficult.

No more confusion than needing to learn that the same set of CSS properties can act in different ways under different conditions. Which is far more confusing, and is why proper software has things such as the separation of concerns mantra, and why things like flag arguments are many times considered a bad thing. They cause mental burden through overloading the meaning of a thing.

This argument also foregoes the complexities of CSS cascade and developers needing to be cognizant of how a layout would respond when as part of some overriding rules with higher specificity, a grid shifts into or out of masonry mode - and which properties related to that should be changed along with it, to continue to achieve the desired layout effects.

Using explicitly split families of properties makes that eminently more clear to read.

It would also ensure flexible and expressive designs, while benefiting from future grid enhancements.

It would likewise also hamstring all future grid enhancements with the need to take into account the alternative masonry mode and could end up limiting the flexibility and expressiveness of grids at the expense of unified syntax that has no clear benefits.

Any future grid enhancements done to the core internal layout mechanics for grid as implemented in user agents, when deemed suitable for use with masonry, can still be surfaced to be enabled for masonry as well. Whereas those that are not deemed suitable, will not have to. And they can still use a shared internal implementation.

The alternative where both are covered in a unified CSS syntax as part of CSS grid, is that either grid can support nothing that masonry cannot also support (and vice versa) - which hamstrings future enhancement immensely - or it will lead to a need to rigorously document which cases of various grid features will work in which mode and which won't; as well as documenting all the edge cases of complex interplay. And just documenting it doesn't solve the problem of developers also having to remember all of it.


I'm going to say +1 for an explicit display:masonry. Yes; it's more verbose - but ultimately more stable; easier to understand; easier to build further upon; and in-fact already more feature rich (@supports) right out the gate.

endymion1818 commented 2 months ago

+1 for display: masonry; it seems significantly different from grid and flex to be it's own thing. Also good work to the team(s) putting this together, be glad to see a native CSS replacement for masonry.js!

angelux commented 2 months ago

I'd like to add my support for integrating masonry layout into CSS Grid rather than creating a separate display: masonry. Combining masonry with Grid could unlock the full potential of Grid's features like subgrid, track sizing, item placement and others. This integration allows for more complex and dynamic layouts that we might not be able to achieve with a standalone Masonry display.

I think the arguments for a separate display: masonry focus too much on the potential simplicity at the expense of functionality. Excluding Grid's powerful features would hinder developers who want or need more than basic layouts. Plus, introducing another display type could lead to confusion and fragmentation in the layout ecosystem.

Some argue that masonry is fundamentally different from Grid because it aligns items in one dimension, but I strongly believe Grid is flexible enough to handle both one-dimensional and two-dimensional layouts. Separating masonry from Grid overlooks this versitality.

TL;DR, integrating masonry into CSS Grid provides greater flexibility and promotes a more cohesive approach to layout design. It makes more sense to enhance the tools we have rather than fragmenting them, IMHO.

rachelandrew commented 2 months ago

@angelux You still get subgrid, track sizing, item placement and so on with display: masonry. That's all defined in the specification for both versions. You can check out the spec that details both here, and an article comparing the two.

nmn commented 2 months ago

This is already a very heated debate, so I'll keep it short. I want express my strong support for adding masonry to display:grid. The fact that it gracefully degrades to a traditional grid is a huge benefit IMO.

But also, masonry layout is already possible (with some constraints) in Grid layout today!

I came up with this example of a masonry layout with pure CSS using grid layout.

What were the compromises?

  1. The need to know the height of each time ahead of time.
  2. Because this relies grid-row: span N to work, row-gap had to be 0 for the math to work, and I had to use hacks for recreating row-gap.

Honestly, even I'm surprised how far we can go with grid layout already. IMO, my solution is ready for production in many cases.

And since grid already does masonry, I think it makes sense to improve the experience of doing that rather than invent a whole new display mode.


Even if there is vehement disagreement, I hope my demo is interesting.

rgembalik commented 2 months ago

I think I prefer display: masonry for the following reasons:

  1. with display: masonry there would be no cognitive complexity while reading and parsing the CSS - it would spell right out the masonry layout used. With a grid, you would have to analyze grid parameters and translate them to how they work with masonry.
  2. The grid is already complex enough and adding a masonry layer to it will further complicate things. I teach less experienced developers quite often and I already can see some learning friction on grid syntax, especially with functions that work only on grids.
  3. grid is about - well - grids. Masonry steps outside of that, at least in one axis. I know, it's a loose comparison, but I think it's a similar case with flex, which is a separate display.
  4. Any feature added to grids in the future would have to be separately explained in terms of how it works with masonry. My gut feeling tells me, that it would lead to more confusion.
j2is commented 2 months ago

Display masonry is better

cat394 commented 2 months ago

@rjgotten, thank you for your detailed response. I'd like to further clarify my position and respond to some of the points you raised.


Fallback Strategy

While it's true that using a JavaScript library might affect performance and download size, sites that rely heavily on a masonry layout (e.g., Pinterest or Tumblr) place a high value on visual consistency. For these sites, switching to an entirely different layout could significantly compromise the user experience. In such cases, using a lightweight JavaScript solution like Masonry.js as a fallback allows for maintaining visual consistency while minimizing performance and size concerns, ensuring a similar user experience across browsers.

Additionally, while it's possible to use @supports to fallback to a different layout, this isn't always practical. For content where visual consistency is crucial, managing multiple fallback layouts increases the burden on developers and complicates maintenance. As a result, JavaScript-based fallbacks can often be a more pragmatic solution for both development and maintenance.


The Benefits of Integrating Masonry into Grid

From what I've observed, creating a typical masonry layout using Grid syntax does not seem to introduce any noticeable complexity. Using Grid as a foundation for masonry layouts feels intuitive and straightforward, especially for developers already familiar with Grid's existing features.

One possible area of concern might be the grid-template-areas property, which may seem less applicable to a masonry layout due to its auto-placement nature. However, since masonry primarily focuses on automatic item placement, I believe this property would not be frequently used in such scenarios.

Additionally, the evolution of Masonry.js has largely stayed within the bounds of what can be accomplished using the current Grid system, suggesting that independent development of Masonry layouts may not be necessary. This reinforces the argument that masonry should evolve as part of the broader Grid system rather than as a standalone feature.


Improving Developer Experience

Using Grid syntax to implement masonry feels natural for developers who are already familiar with Grid. This reduces the need to learn new concepts and allows developers to apply existing knowledge effectively.

An important point to consider is that Firefox Nightly and Safari Technology Preview already support masonry layouts within the Grid system, and we haven't seen any major complaints from developers about this implementation. This lack of negative feedback suggests that the developer experience when using masonry within Grid is already quite positive and intuitive.

If there are specific examples where integrating Masonry into Grid could confuse developers, I'd appreciate it if you could share them. So far, I haven’t come across any such issues.


Lack of Independent Evolution in Masonry.js and Its Relationship with Grid

Masonry.js has been around for a long time, and while it has evolved, it has primarily done so within the constraints of what can be achieved using the existing Grid system. This suggests that there hasn't been a strong need for Masonry to evolve independently outside the scope of Grid. Most of the features needed for masonry layouts can already be handled by Grid, further supporting the argument that Masonry doesn't require independent evolution and should be part of the Grid system's future development.

Conclusion

Integrating Masonry into Grid would reduce the learning curve for developers by allowing them to reuse existing properties, minimizing the burden of adopting new concepts. Additionally, the fact that Masonry.js has not evolved beyond what the current Grid system can achieve indicates that independent evolution isn't necessary.

If those who support display: masonry; believe there are specific reasons or properties that justify the independent evolution of Masonry, I’d be keen to hear them.

rachelandrew commented 2 months ago

If those who support display: masonry; believe there are specific reasons or properties that justify the independent evolution of Masonry, I’d be keen to hear them.

In addition to the post on the Chrome blog that outlines a number of places where masonry in grid has the potential to be confusing, I've outlined (as someone who has been teaching CSS for about 25 years) why it's confusing, and not particularly ergonomic, due to the fact the best defaults are different—Masonry and good defaults.

Reusing existing properties is more confusing, not less, if those properties behave in different ways.

As for there not being complaints from developers about the existing implementations, those implementations are experimental, so very very few people will have done any more than a quick demo, and those people are likely to be very experienced with CSS (as those are the folks who like to play around with experimental CSS). So that's just not a great signal, and is why making these decisions is hard, and why people who have experience teaching the language can help, as we do get a read on what people find hard.

cat394 commented 2 months ago

@rachelandrew, thank you for your response!


In addition to [the post on the Chrome blog that outlines a number of places where masonry in grid has the potential to be confusing, I've outlined (as someone who has been teaching CSS for about 25 years) why it's confusing, and not particularly ergonomic, due to the fact the best defaults are different—Masonry and good defaults.

It seems I misunderstood your point about the Chrome blog. Apologies for that. Upon reviewing the comparison of the two syntaxes there, I didn't observe any odd CSS hacks or complexities when using the Grid syntax.

While I understand that some proponents of display: masonry; argue that the current Grid system is "too complex," they often fail to specify which aspects of Grid are confusing for beginners or what exact part of the specification is causing difficulties.

As for the "complexity of grid," I believe that many developers may find challenges not with the layout system itself, but with concepts like the fr unit and how functions like min(), max(), and minmax() are combined to create responsive designs. These issues don't seem directly related to the complexity of the grid.

Regarding your point about the lack of complaints from developers using Firefox Nightly or Safari Technology Preview due to the experimental nature of the implementation, I agree that the usage is currently limited.

lucasmicheli commented 2 months ago

Hello all! After reading most of the blog posts out there considering both options' pros & cons, I'm more confident with the display: masonry option mainly because Grid is already full of possibilities but difficult to teach to fellow current and future developers. I think it would be better to have a 'clean slate' on this matter, since it's already hard to 'guide' someone on the many options Grid presents nowadays. I envision masonry as more similar in syntax to Flex, which is by far more easy to remember. So, +1 for display: masonry. Thanks!

jjhiggz commented 2 months ago

+1 for display: masonry I think A: grid is already confusing as it is B: Masonry's mental model isn't two dimensional IMO. It's one dimensional with a wrap. Thinking about it as X,Y doesn't make sense and to me that's what "Grid" means

nmn commented 2 months ago

Firstly, I want to say that both approaches would be acceptable and the new functionality would be a very welcome change.

I just want to address one of the biggest arguments in favour of display: masonry.

Reusing existing properties is more confusing, not less, if those properties behave in different ways.

I agree with this statement, but I don't think it's fair to say the "properties behave in different ways" when using grid-template-rows: masonry within display: grid. From everything I have read, using masonry within grid stays completely consistent to grid layout and just adds the option of "don't create rows that span all columns, just stagger them as needed instead". aka. masonry. This feels quite intuitive to me.

Now, I don't think the display: masonry solution is any less intuitive, specially because it more or less takes all the same properties from display:grid and re-uses them as is or with slightly different property names.

My biggest concern with display: masonry is that it might lead unnecessary fragmentation of APIs as the two display modes evolve over time.

The flipside of this is that this "fragmentation" can also bring some benefits such as:

However, seeing the examples so far, it feels like the fragmentation is leading to more cons than pros. For example, one of the proposed features of display: masonry is to have auto-sized columns based on the content. This is currently not a feature of display: grid. I don't think this is an argument in favour of display: masonry but an argument in favour of bringing the same feature to display: grid.

nileshprajapati commented 2 months ago

+1 for display:masonry

rjgotten commented 2 months ago

@nmn For example, one of the proposed features of display: masonry is to have auto-sized columns based on the content. This is currently not a feature of display: grid.

That particular proposal is possible with display: masonry and not with 'masonry ~in~ expressed as grid' precisely because of splitting the layout models. Grid layout was explained before as it not being possible -- or at least in any performant manner -- to combine auto-repeat with auto-size. The reason is actually simple: items have to align on the main axis and the cross axis. This means computing the ideal distribution of wrapping items into multiple rows/columns is really, really hard. Because what you gain on any axis, you might lose a lot on the other. And there are complex interdependencies of height vs width to consider as well. (Hello aspect-ratio) Not to mention how that fits together with explicit placement and implicit placement combinations. Woo-boy!

With masonry you don't have that computational complexity problem, because it only is in alignment on one axis.

This is in fact an example of, should masonry be implemented inside grid, a case where grid would hamstring the feature richness of masonry. Not a case of where a feature developed for one could also flow into the other.

nmn commented 2 months ago

@rjgotten If what you're saying is true, then yes, it would be a good argument for splitting the display modes. However, from everything I've read that is not the case. At least, not anymore. The Chrome blog specifically mentions that they found a solution to the performance problem.

With masonry you don't have that computational complexity problem, because it only is in alignment on one axis.

You're hand-waving away a lot with that one sentence. From everything I can gather and think through, the only difference between masonry and traditional grids is whether rows are staggered or aligned across columns. The column widths themselves would need to be calculated in exactly the same way.

If I'm wrong about this please correct me and explain how masonry changes how columns would be calculated intrinsically.


To explain my own thought process:

The most naive approach for both traditional and masonry grids would be to start by picking the first N children that can fit in the first row.

And if you have dense grid: If you have some space left after placing n children and the n+1th element is too big to fit in that space, look for the next child that can fit in that space.

And then...

Place the rest of the children along the columns defined by the first row. Every child would go to the first column where it fits, but if it doesn't fit in any of the columns, it would go to the next available column.

And in a dense grid: If any columns are skipped and a subsequent child can fit there, fill it.


Where I could be wrong

The biggest open question left in my thinking is if there would be some kind of automatic intrinsic behaviour for grid-column: span. Should children in the grid automatically span multiple columns in either of the two layouts?

Again, I think whatever the answer to that is, it is an answer that would apply equally to both layouts.


I will happily change my view completely if I'm presented any evidence for why automatically defining columns is possible for masonry but not grid. But for now, I see it as an artificial fragmentation of features that is being made available to one layout but not the other and this is one of the big reasons I think adding masonry to grid is the better solution. It forces us to design APIs to a higher standard for the future and not take the easy way out and create fragmentation.

Loirooriol commented 2 months ago

The column widths themselves would need to be calculated in exactly the same way.

No, see https://drafts.csswg.org/css-grid-3/#track-sizing

firefoxic commented 2 months ago

As much as I'd like to save Mozilla some extra work (and Firefox Nightly already has an experimental implementation with grid-template-rows: masonry), my vote is for display: masonry. Because it's neither in meaning nor appearance a grid anymore. And it doesn't seem like a good idea to complicate the CSS Grid Layout spec even more.

tabatkins commented 2 months ago

@nmn Right, as @Loirooriol points out, we do indeed have a substantially different track sizing algorithm between the two modes. Masonry ends up eventually invoking the Grid Layout algorithm in a specific, restricted way, and only after doing some collection/massaging of the items. The biggest difference is that we pretend that each masonry item is placed in every possible track that it could go in, since we can't actually tell what track it will end up in until layout time, after we've already sized the tracks.

One of the side effects of this is that Masonry can reasonably define a behavior for repeat(auto-fill, auto) (or any other combination of intrinsically-sized tracks with the auto-fill/auto-fit keyword). It's somewhat heuristic in complex cases, but for simple cases gives an accurate sizing result for the tracks, and thus an accurate repetition count. Grid can't reasonably do the same, because Grid Layout makes different assumptions about how its grid items work; it's theoretically possible to define something for it, but it would produce results substantially further away than what Grid would normally produce.

cat394 commented 2 months ago

I was making the argument under the assumption that Masonry will not evolve independently from the grid. If @rjgotten's opinion is correct, I will change my opinion and support display: masonry;.

If a concrete example, as suggested by @nmn (although it's still in the proposal stage), had been presented showing that masonry is incompatible with the existing grid layout, I believe no one would have objected to the proposal of display: masonry; in the first place...

nmn commented 2 months ago

each masonry item is placed in every possible track that it could go in

@tabatkins I'm still reading the spec and trying to make sense of this. What does this mean when it comes to determining the size of the columns? Are we choosing the maximum width of all masonry items? Wouldn't one wide element cause all columns to become very wide as a result? Does the repeat(auto-fill, auto) for masonry always return in equal width columns?

seezee commented 2 months ago

After reading about the issues at https://developer.chrome.com/blog/masonry-syntax, I'm convinced display: masonry is the way to go, even though it means I'll have to change my stylesheet for at least one project when the spec is finalized and adopted.

andrei9669 commented 2 months ago

overall, I support grid masonry as it adheres to familiar API and I don't have to remember that much extra stuff. Now, if display: masonry would have it's own "unique" syntax and would have no resemblance to grid, then it's fine to keep them separate. But, if they start sharing syntaxes then I'm afraid it will cause more confusion as developers would have to remember which syntax applied to which display and how it behaves + the defaults would also be different.

On the complaints that the grid is already complex enough, as @cat394 said, I'm also interested in what specifically is complex about it that masonry would increase. as I understood from chrome blog post, they have achieved similar performance on both approaches so the only discussion is about the syntax of it.

keithjgrant commented 2 months ago

I thought I'd commented here already, but perhaps that was on an older issue. As a writer/teacher of CSS, I strongly support display: masonry, primarily because I think it has an easier learning path. Not because it's easier for developers that already have a solid understanding of grid, but because I think it will be easier for developers that don't, or only have a cursory grasp on grid. I think getting reasonable default values by declaring display: masonry is a better outcome than having to learn grid, then ignore the parts that aren't relevant, and apply the rest.

I've written more of my thoughts here.

SKOLZ commented 2 months ago

on one hand, having masonry inside of display: grid would be beneficial because you'd have to learn a variant of a structure you already know. But on the other hand, I think having it as display: masonry would be better since masonry is quite a specific case and it would make the display grid property even more complex. So I'd go with display: masonry to simplify its usage, learning, and adoption.

el22or commented 2 months ago

My vote is for display: masonry!

nathanchase commented 2 months ago

display: masonry

Succinct. Clear. Easy to implement. Extendable. Doesn't have to crowd and further complicate "grid" - which already has plenty of its own properties.

Seems like a no brainer.

cat394 commented 2 months ago

The Masonry syntax that surprised me the most when I first saw it on the Chrome blog was this:

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(3, 1fr);
  masonry-direction: column-reverse;
}

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

This goes against my intuition, and I feel it could be confusing for many developers.

Modern frontend developers have become so accustomed to grid layouts.

Many people feel that grid layouts and masonry layouts are quite similar in design.

Grid and masonry layouts are fundamentally different layout mechanisms.

However, the fact that you can write masonry layouts using the familiar grid syntax is something I believe would captivate many developers.

I was able to achieve my desired layout using the masonry keyword in the current Firefox Nightly, and I did not experience any behavior that went against my intuition.

In fact, I found it easy to work with because I could use the existing Grid API as-is.

I trust my own experience over the "future" or "possibility" that some so-called experts try to sell.

luis-pato commented 2 months ago

👍 for display: masonry. I think using display: masonry would be much clearer than using display: grid. Having some of the "grid settings" behave differently when used with display: grid or display: masonry would be confusing, difficult for beginners to learn, and likely prone to errors.

Even though I will probably use this feature very rarely, I’m quite excited about it! 😄

firefoxic commented 2 months ago

Grid and masonry layouts are fundamentally different layout mechanisms.

@cat394 That's the only thing I can agree with.

rjgotten commented 2 months ago

@cat394 The Masonry syntax that surprised me the most when I first saw it on the Chrome blog was this:

.masonry {
  display: masonry;
  masonry-template-tracks: repeat(3, 1fr);
  masonry-direction: column-reverse;
}

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

This goes against my intuition, and I feel it could be confusing for many developers

Masonry is single-axis and masonry-direction takes after flex-direction. What that property says is the masonry layout goes 'column first; in reverse order'

willetto commented 2 months ago

My vote is for display: masonry

I'm sorry I don't have a pretty markdown comment, but I have read through the issue and a couple of write ups and much prefer the display: masonry syntax.

Thank you to the working group for deliberating on this.