Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[css-grid] grid-gap is still taking up space when an element defined in grid-template-area is not on the page. #5813

Open
bramdoppen opened this issue Dec 21, 2020 · 33 comments
Labels
css-grid-3 Masonry Layout

Comments

@bramdoppen
Copy link

Hi all! Love the work you do, but there is one thing that I would like to mention here: grid-gaps that are still taking up space when element is not in the DOM.

It works when all elements are present
Everything is fine here. Nice gaps between elements.
2020-12-21 12_55_54-Window

The issue:
When the last element (the filter) is removed from the page (but is still defined in the grid-template-area) the row-gap is still taking up space.

2020-12-21 12_56_07-Window

2020-12-21 12_58_59-DevTools - pggmenco nl perplex self_werk-en-prive-in-balans_

Would be great if css grid would not add those row-gaps in the future.
Did some research but there is no rock-solid workaround that I can use right now, or am I missing something?

@SebastianZ
Copy link
Contributor

What you can do right now is define your grid differently when one of the elements is not in the DOM or not displayed.

In your example this means to only specify the "picture" and "content" areas and only two grid-template-rows.

Another solution for this would be allowing to define different gap sizes as discussed in #1659.

Besides those two approaches, I think a general solution for this would be to have a way to control whether to collapse gaps adjacent to empty grid tracks - something like a gap-collapse property with the values none and adjacent.

Sebastian

@fantasai fantasai added the css-grid-3 Masonry Layout label Dec 30, 2020
@fantasai
Copy link
Collaborator

fantasai commented Dec 30, 2020

I suspect we can't do it by default at this point anymore, but collapsing gaps seems like a good way to go here. We kinda do it already for auto-fit repeats. Might make more sense to take the same values as border-collapse though. :)

@MatsPalmgren Thoughts?

@bramdoppen
Copy link
Author

bramdoppen commented Jan 4, 2021

@SebastianZ Thanks for your reply!

Allowing to define different gap sizes would be awesome, but it would not be a perfect solution for this issue.

Something like a gap-collapse property would solve this issue and it will be a gread addition to grid!

@pavelspichonak
Copy link

@bramdoppen maybe you found some new workaround? To have multiple css classes with different grid-template-areas when you have a lot of blocks and any block can be removed from page, it is a pain.

@bramus
Copy link
Contributor

bramus commented Aug 2, 2023

Collapsing gaps came up again today, where an author added position: absolute to empty grid cells to achieve exactly that (demo).

Would be nice if there was a property to control this, as already hinted above by @bramdoppen.

@bramdoppen
Copy link
Author

@bramus Thanks for bringing this to my attention again. I'm blown away by the position: absolute; solution. Didn't thought that that would work.
But still, it would be nice if there was an option to control this. Any thoughts on this @fantasai @SebastianZ

@bramus
Copy link
Contributor

bramus commented Aug 3, 2023

@bramdoppen Adding display: none; to :empty cells also works, but it was pointed out to me that this can causes issues when you need it to be an aria-live region.

@SebastianZ
Copy link
Contributor

But still, it would be nice if there was an option to control this. Any thoughts on this @fantasai @SebastianZ

Well, I already threw in my idea of a gap-collapse property. And it seems everyone here in this thread is positive about adding this feature. So I'll bring it to the agenda.

Sebastian

@Loirooriol
Copy link
Contributor

In this thread I just see references to collapsing gaps, but the current spec only has this concept for the gutters of a collapsed track.

It's not clear to me what this proposal would do if the track is defined to be e.g. 100px. I don't think it makes much sense to collapse gaps if the track won't end up being zero. But it gets tricky because e.g. an auto track sizing function may end up producing a 0px track, or something bigger, and we don't know until the end of the track sizing algorithm, but the track sizing algo needs to know which gutters are collapsing.

I guess it could be restricted to collapsing the gutters adjacent to empty tracks whose min track sizing function is either a fixed 0px or intrinsic, and whose max track sizing function is 0px or intrinsic but not auto.

But I think it would be simpler to reuse the existing concept, and instead of adding a feature to only collapse gutters, add a feature to collapse empty tracks (and the adjacent gutters will collapse too).

Like empty-tracks: collapse | auto, where collapse (or maybe hide to align with empty-cells?) would collapse all empty tracks, and auto would only collapse the empty tracks generated by an auto-fit repetition.

@SebastianZ
Copy link
Contributor

In this thread I just see references to collapsing gaps, but the current spec only has this concept for the gutters of a collapsed track.

It's not clear to me what this proposal would do if the track is defined to be e.g. 100px. I don't think it makes much sense to collapse gaps if the track won't end up being zero.

I agree. That's what I meant when I wrote "have a way to control whether to collapse gaps adjacent to empty grid tracks" but that wording was obviously ambiguous.

But I think it would be simpler to reuse the existing concept, and instead of adding a feature to only collapse gutters, add a feature to collapse empty tracks (and the adjacent gutters will collapse too).

Like empty-tracks: collapse | auto, where collapse (or maybe hide to align with empty-cells?) would collapse all empty tracks, and auto would only collapse the empty tracks generated by an auto-fit repetition.

That probably covers a lot of use cases. Though I also have an example in which this wouldn't work:

Use case for grid gap collapsing without track collapsing

In that widget, the image on the left spans across all grid rows, so they are not empty. The contents on the right are placed in individual grid cells. The rows are defined as 1fr repeat(4, min-content) 1fr. So one of the cells on the right is not filled. This gets obvious when a row-gap is added:

Same screenshot as above but with row-gap applied to show the empty cell

In this case, it would make sense to collapse the adjacent gaps plus the 0-width track to always keep the contents on the right vertically centered.

So the two cases, empty and 0-width should be controllable. Not sure whether they should be handled individually or together. Though I agree that this new feature should affect collapsing both tracks and gutters.

Sebastian

@fantasai
Copy link
Collaborator

I think this issue needs a more concrete proposal before it's useful to bring it up to the WG.

@astearns astearns removed the Agenda+ label Sep 26, 2023
@Loirooriol
Copy link
Contributor

My proposal in #5813 (comment) is quite concrete: just add a property that controls whether empty tracks should collapse. The concept of collapsing a track is already defined in the spec, so no need to invent anything complicated.

I think it's fine that it doesn't cover Sebastian's testcase, since that would probably be better addressed with a nested grid anyways.

@devongovett
Copy link
Contributor

Would be amazing to make some progress on this. I've found it really difficult to use CSS grid for complex layouts with optional slots because the gaps between columns/rows do not collapse when the adjacent column/row is otherwise unused. Usually we have to go back to using manual margins on children so that when they are not there the gaps collapse, but this has other problems that were originally solved by gaps. Another solution is to not use grid at all and to use flex instead, but this requires additional DOM wrappers that can be hard to insert in the right places (especially with responsive layouts where children move to different slots depending on the screen size).

What is missing for this to be discussed? I think the above proposal for gap-collapse would work. The behavior would be to merge multiple adjacent gaps into a single one, similar to what border-collapse does in tables.

@SebastianZ
Copy link
Contributor

Given that everybody is positive about adding this feature and @Loirooriol's proposal, I think we're in a good position to get a resolution on this.

I think the main point for discussion is whether we can and should include the use case I previously outlined in the algorithm.
The other thing is bikeshedding the name and values. There was a lot of positive feedback on my initial proposal on a gap-collapse property. Though I get @Loirooriol's point that this also covers collapsing tracks and not just gutters.

Sebastian

@astearns astearns moved this to Unsorted in CSSWG June 2024 meeting Jun 3, 2024
@fantasai fantasai moved this from Unsorted to Tuesday morning in CSSWG June 2024 meeting Jun 10, 2024
@fantasai fantasai moved this from Tuesday morning to Tuesday afternoon in CSSWG June 2024 meeting Jun 10, 2024
@MrHBS
Copy link
Contributor

MrHBS commented Jun 12, 2024

I am assuming this was not discussed in yesterday’s meeting?

@fantasai
Copy link
Collaborator

I think we should try for an auto behavior that could be enabled by default on a website (ideally, if Web-compat allows it, as the initial value). It seems unlikely that people want empty zero-sized tracks to contribute gaps, so it would be a better default behavior to collapse the gaps on such tracks.

Suggestion is values show | hide | auto where hide collapses empty tracks regardless of their size and auto collapses an empty grid track (merges the gaps on either side) if:

  • track is empty AND
  • minimum size is zero or content-based AND
  • maximum size is content-based AND
  • its maximum size is not auto OR content alignment is not stretch/normal OR there's a flexible track (i.e. this empty track can't absorb extra space)

For grid a track is empty if:

  • no item is placed in it or spans across it

For masonry the track is empty if

  • same condition as grid wrt explicitly-placed items AND
  • no auto-placed tracks at all

@SebastianZ I think it makes sense to address the case you outlined with spanners; it doesn't seem unusual at all. To do that, we need to know which of the various tracks to collapse if all the spanned tracks are otherwise empty: do we prioritize keeping the first track? the largest track? the track with the most items (unless there's a tie, then what)?

@SebastianZ
Copy link
Contributor

@SebastianZ I think it makes sense to address the case you outlined with spanners; it doesn't seem unusual at all. To do that, we need to know which of the various tracks to collapse if all the spanned tracks are otherwise empty: do we prioritize keeping the first track? the largest track? the track with the most items (unless there's a tie, then what)?

Do we need prioritization? I assumed, it would be sufficient to extend the track sizing algorithm to say that all spanned tracks that end up being zero-width will be collapsed.

Sebastian

@Loirooriol
Copy link
Contributor

@SebastianZ We need to know which tracks collapse before the track sizing algorithm (since the presence of gaps affects the result of the track sizing algorithm).

@sir-captainmorgan21
Copy link

What would be a best guest timeline on this being generally available across major browsers or through polyfills? This would allow for a truly flexible grid where all items could be optional and move independently

@SebastianZ
Copy link
Contributor

@Loirooriol Right, but the track sizing algorithm is already run twice for row and column sizes in the grid sizing algorithm. So we could say that in steps 3 and 4 we base re-resolving the sizes and collapsing gaps on whether the tracks are zero-width at that point.

@sir-captainmorgan21 This issue is still being discussed and there is no resolution yet. So it is way too early to predict when this will be available in any browser, let alone in all of them.

Sebastian

@fantasai
Copy link
Collaborator

fantasai commented Aug 20, 2024

@SebastianZ I think I agree with @Loirooriol that we should determine which tracks to collapse before doing track sizing.

I guess one solution would be that we keep the track(s) with the most items in it (i.e. keep both if there's a tie). I think that does a reasonable job of handling most spanning relationships?

@Loirooriol
Copy link
Contributor

Loirooriol commented Aug 21, 2024

@fantasai I'm not sure if extra complexity of the auto value is really worth it, but not opposed.

minimum size is zero or content-based

What exactly is "zero"? Just 0px? What about 0% with a definite grid container size, that's probably zero too? What about a 100% that resolves against 0px? What about an indefinite percentage, do we treat it as auto during intrinsic sizing (so typically not collapsing tracks due to the stretching) and then collapse tracks if the percentage resolves to 0px when laying out for real? Or if not stretching auto, we collapse percentage tracks during intrinsic sizing but not when laying out for real if the percentage resolves to a positive length? That could easily lead to overflow.

no auto-placed tracks at all

Why is this needed?

we need to know which of the various tracks to collapse if all the spanned tracks are otherwise empty

I'm not sure if I follow. In @SebastianZ's example, not all of the spanned rows are otherwise (ignoring the image) empty.

@SebastianZ I would prefer to avoid extra passes of the sizing algorithm.

@SebastianZ
Copy link
Contributor

@SebastianZ I would prefer to avoid extra passes of the sizing algorithm.

I am imagining only an extra step (which is necessary in any case we want to solve this), not an extra pass.
Maybe this check could actually be part of the grid sizing algorithm, right after step 2. So the track sizing algorithm already ran once for rows and columns.

And regarding "zero", I'd expect this to include any track that does not take up any space at that point, independent of whether that's 0px or 0%.

Sebastian

@fantasai
Copy link
Collaborator

What exactly is "zero"? Just 0px? What about 0% with a definite grid container size, that's probably zero too?

I think for simplicity, it might be best to just take zero lengths here.

Why is this needed?

Because in masonry layout, auto-placed items contribute sizing to every track.

I'm not sure if I follow. In @SebastianZ's example, not all of the spanned rows are otherwise (ignoring the image) empty.

Yes, but if they were otherwise empty, then we need to figure out what to do.

@Loirooriol
Copy link
Contributor

If I understand it correctly, the proposal to handle spanning items, is that:

  • For empty-tracks: hide, we collapse tracks not marked as filled by some item. For empty-tracks: auto there are more conditions on the track sizing functions.
  • Non-spanning items just mark their track as filled
  • Spanning items mark the spanned tracks with the greatest number of items as filled

So for example, if item A spans tracks 1-5, item B spans tracks 1-5, item C spans tracks 3-7, and item D spans tracks 6-8

1 2 3 4 5 6 7 8
A A A A A
B B B B B
C C C C C
D D D

Then A,B,C mark tracks 3-5 as filled, and D marks tracks 6-7 as filled. So we collapse tracks 1-2 and 8. Is that right?

@SebastianZ
Copy link
Contributor

SebastianZ commented Aug 25, 2024

@Loirooriol It's hard for me to imagine how the algorithm should work in that case given your example. Therefore, I've created a few Codepens using your example. Based on them, I'll describe what I'd expect regarding collapsing.

Collection: https://codepen.io/collection/RzMBaZ

repeat(8, min-content)

https://codepen.io/SebastianZ1983/pen/vYqrEJr

Tracks and gaps should collapse so that the result is the same as if gap weren't set.

repeat(4, 100px min-content)

https://codepen.io/SebastianZ1983/pen/XWLYJZM

Tracks 2, 4, 6, and 8 should collapse.

repeat(2, max-content 100px min-content 50px)

https://codepen.io/SebastianZ1983/pen/wvLXBXV

Tracks 1, 3, 5, and 7 should collapse.

200px 1fr 1fr repeat(5, 100px) with restricted container width

https://codepen.io/SebastianZ1983/pen/ExBRadw

Tracks 2 and 3 should collapse.


I'll add more examples and their expected outcome on demand.

If I understand the hide value correctly, it behaves the same as auto but also collapses empty tracks regardless of their size. If so, I wonder if this has any use cases and if this shouldn't be discussed separately, as the use cases outlined so far refer to zero-width tracks.

Sebastian

@Loirooriol
Copy link
Contributor

@SebastianZ Note I'm not proposing that algorithm, it's just my guess of what fantasai might have in mind.

Tracks 2, 4, 6, and 8 should collapse.

I think fantasai's idea wouldn't collapse 4 as per "we keep the track(s) with the most items in it (i.e. keep both if there's a tie)".

Tracks 1, 3, 5, and 7 should collapse.

Ditto for 3,5.

Tracks 2 and 3 should collapse.

A priori we don't know if the 1fr will have any free space to grow, so this would need multiple passes of the track sizing algorithm, which I don't like.

If so, I wonder if this has any use cases and if this shouldn't be discussed separately, as the use cases outlined so far refer to zero-width tracks.

The original use case at the top of this issue is about having tracks for optional elements that may or might not exist. Thus hide is a much more straightforward way to achieve this. On the opposite, I'm still not super convinced that the complexity of auto is actually worth it. The only use case that I have seen is your spanning case, which it seems that could be addressed with a nested grid.

@fantasai
Copy link
Collaborator

If I understand it correctly, the proposal to handle spanning items, is that [...]

@Loirooriol Yes, that's a great example.

repeat(8, min-content)

Tracks and gaps should collapse so that the result is the same as if gap weren't set.

I think you are wrong here @SebastianZ. If you requested gaps, then we must put one at least between 5/6.

repeat(4, 100px min-content)
Tracks 2, 4, 6, and 8 should collapse.

What if track 7 doesn't have enough space for item D? I think we would want to avoid automatically creating overflow, especially since the author's specified design avoids such overflow.

200px 1fr 1fr repeat(5, 100px) with restricted container width
Tracks 2 and 3 should collapse.

I agree strongly with @Loirooriol that we should not make track collapsing depend on the available space. If nothing else, it creates a discontinuity.

Thanks @Loirooriol and @SebastianZ for all the examples.

@SebastianZ
Copy link
Contributor

@SebastianZ Note I'm not proposing that algorithm, it's just my guess of what fantasai might have in mind.

And the expectations I posted were not an interpretation of fantasai's algorithm but what I'd expect as an author.

Tracks 2, 4, 6, and 8 should collapse.

I think fantasai's idea wouldn't collapse 4 as per "we keep the track(s) with the most items in it (i.e. keep both if there's a tie)".

That's what I understood as well, though again, in the examples I thought of an author's perspective, not about the proposed algorithm.

Tracks 2 and 3 should collapse.

A priori we don't know if the 1fr will have any free space to grow, so this would need multiple passes of the track sizing algorithm, which I don't like.

Again, not multiple passes. My suggestion was to choose the tracks to collapse after the first pass instead of before as suggested by you and fantasai. At that point we should know whether the 1fr resulted in zero-width tracks.
But you both know the algorithm better than me, so maybe you can clarify why it's a bad idea to choose them afterwards.

If so, I wonder if this has any use cases and if this shouldn't be discussed separately, as the use cases outlined so far refer to zero-width tracks.

The original use case at the top of this issue is about having tracks for optional elements that may or might not exist. Thus hide is a much more straightforward way to achieve this.

I think I misunderstood hide initially. I thought it would be based on auto but disregard the track sizes. After re-reading, hide only targets completely empty tracks, so disregards any spanned-over tracks and zero-width logic. So it targets the use case outlined in the first comment.

On the opposite, I'm still not super convinced that the complexity of auto is actually worth it. The only use case that I have seen is your spanning case, which it seems that could be addressed with a nested grid.

There are different ways to achieve this right now for my use case. Nesting grids, though that also requires nested DOM structures. Or :has() can be used with different grid-template definitions, which also solves the use case of comment 0. Both approaches are much more cumbersome to write than an empty-tracks: auto, especially if web compatibility allows to make this the default as suggested by @fantasai.

repeat(8, min-content)

Tracks and gaps should collapse so that the result is the same as if gap weren't set.

I think you are wrong here @SebastianZ. If you requested gaps, then we must put one at least between 5/6.

Based on your algorithm, yes. Based on author intention, it's unclear.

Though I'd also note that a grid with only spanning items which overlap in several tracks, is an edge case.

repeat(4, 100px min-content)
Tracks 2, 4, 6, and 8 should collapse.

What if track 7 doesn't have enough space for item D? I think we would want to avoid automatically creating overflow, especially since the author's specified design avoids such overflow.

So if item D is wider than track 7, tracks 6 and 8 are non-zero-width, and therefore don't collapse.

200px 1fr 1fr repeat(5, 100px) with restricted container width
Tracks 2 and 3 should collapse.

I agree strongly with @Loirooriol that we should not make track collapsing depend on the available space. If nothing else, it creates a discontinuity.

I'd argue that this is similar to the min-content cases, at least in my understanding of how the algorithm could handle this.

Though I get your point about discontinuity, as tracks may collapse or not depending on the available space.

Sebastian

@astearns astearns removed the Agenda+ label Aug 28, 2024
@SebastianZ
Copy link
Contributor

So, to summarize where we are right now:

Sebastian

@Loirooriol
Copy link
Contributor

Consider a grid with two minmax(auto, max-content) columns, one small item in the 1st column, and a 2nd big item spanning both columns.

Currently, the algorithm will size the 1st column tightly around the 1st item, and the remaining size of the 2nd item will be accommodated by the 2nd column.

With fantasai's proposal of spanning items and empty-tracks: auto by default, then we would collapse the 2nd track, so the 1st column will grow to accommodate both items. I don't think this would be web compatible.

Even if empty-tracks: auto isn't the default, I'm not convinced that collapsing the 2nd track is desirable.

Maybe this check could actually be part of the grid sizing algorithm, right after step 2.

Steps 3 and 4 are only needed when there are things like aspect ratios or orthogonal flows, with this they would need to run more frequently.

@Loirooriol
Copy link
Contributor

Loirooriol commented Aug 28, 2024

My proposal to move this forward is just adding empty-tracks: hide (or collapse?) for the moment, which will collapse all empty tracks regardless of their track sizing function. Tracks containing spanning items are never considered empty.

This should address the original usecase, and be simple to spec and implement (since we are already doing that for auto-fit repetitions).

Then open other issue(s) about new value(s) to only collapse when the track would be guaranteed to be 0px, and to consider tracks containing spanning items as empty in some cases.

@keithamus
Copy link
Member

Is this worth adding to the agenda? I'd quite like to see this progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-grid-3 Masonry Layout
Projects
Status: Tuesday afternoon
Status: Thursday Afternoon
Development

No branches or pull requests