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-2] subgrid and grid-gap #2285

Closed
Dan503 opened this Issue Feb 7, 2018 · 31 comments

Comments

Projects
None yet
8 participants
@Dan503
Copy link

Dan503 commented Feb 7, 2018

https://www.w3.org/TR/2018/WD-css-grid-2-20180206/#subgrids

In the article "Why display: contents is not CSS Grid Layout subgrid" by Rachel Andrew, she points out an extremely common use case for why we need subgrid. As far as I can tell, the current version of the spec is not able to support this use case.

My issue is around how subgrid is supposed to work around the grid-gap property.

The spec currently says this:

https://www.w3.org/TR/2018/WD-css-grid-2-20180206/#valdef-display-subgrid
If the element is a grid item ... this value makes the element a subgrid ... and consequently ignores its grid-template-* and *-gap properties in favor of adopting the parent grid tracks that it spans.

In the examples in the article, each card is surrounded by a 20px grid-gap. If the items inside each card were to strictly align to the grid cells of the outer grid, then there would also be a 20px gap between the title, image, content and footer. We want each card to be separated by that 20px gap but we also want each item inside the card to sit hard up against each other. That isn't possible if the grid-gap property is ignored.

I think by default, the subgrid should inherit whatever the parent grid-gap property is. That's fine and could cut down on repetition if that is the behavior you want. However, we need to be able to override this behavior by setting the grid-gap property on the subgrid element. That way the items inside each card can then sit hard up against each other while the cards themselves can still enjoy a nice 20px gap between them.

.card {
  border: 4px solid rgb(24,154,153);
  background-color: #fff;
  grid-row: auto / span 4;
  display: grid;
  grid: subgrid;

  /*
    Overrides parent grid-gap setting.
    Causes cells inside subgrid to sit hard up against one another
  */
  grid-gap: 0;
}
@fantasai

This comment has been minimized.

Copy link
Contributor

fantasai commented Feb 8, 2018

Well... We can re-use the normal keyword (which is the initial value) to give the copy-from-parent behavior while allowing customization inside. It's maybe a little tricky to handle in the sizing algorithm, since gaps are currently specified as behaving just like tracks, but I think we could add the difference between the subgrid's gaps and the parent's gaps as “pretend margin” on the individual items.

Note that right now, if I have a 3-column grid with 200px columns and 20px gaps, it is 660px wide, to accommodate both the columns and the gaps. What you're suggesting means that inside a subgrid, we could specify a different gap size, and the columns would be wider/narrower than the specified size.

@mrego

This comment has been minimized.

Copy link
Member

mrego commented Feb 8, 2018

I believe a simpler approach for the example would be to add a margin to the subgrid element, instead of using gutters on the parent grid.

If we use gutters in the parent grid I don't see how we can change its size in the subgrid, the idea of subgrids is to share the track sizes with the parent, we'll be losing that as @fantasai explains, so I'm not convinced this is a good idea.

An example of a grid with 2 columns: grid-template-columns: 200px 100px. That in the 2nd row as a subgrid.
On the first image it keeps the gap from the parent, so the size of the tracks are still 200px 100px.
On the 2nd one it removes the gaps, so the size of the tracks in the subgrid would be 225px 125px. Which would be quite strange.

Example of subgrids with different gaps

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Feb 8, 2018

I don't think it's that strange. If I set grid-gap: 0 on the sub grid that is exactly what I would expect to see.

What is a bit more awkward is if the subgrid grid-gap setting is greater than it's parent grid-gap size. That would most likely need to be resolved by eating into the grid cell column/row sizes or you could make the maximum gap size on sub grids the size of the outer grid-gap. That wouldn't be as useful though.

I'm really not fond of the idea of having to go back to using margin. It's immensely more difficult to use than grid-gap for adding spacing between grid cells :(

@mrego

This comment has been minimized.

Copy link
Member

mrego commented Feb 8, 2018

I don't think it's that strange. If I set grid-gap: 0 on the sub grid that is exactly what I would expect to see.

By strange I meant that you've a grid container with 2 columns of a fixed size (grid-template-columns: 200px 100px), but a subgrid of that container has different sizes for these tracks.

And if you go to more complex cases, what happens if you have grid-template-columns: 200px 1fr with a grid-column-gap: 50px. And you want to remove the gap in the subgrid of the 2nd row (like in the previous picture).
What should be the size of the first column in the subgrid? 200px or 225px? Shouldn't the 1fr take the space of the gap?

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Feb 8, 2018

I don't think it's that difficult to comprehend.

The gap would always base itself on where the center of the grid line is and work outwards from there.

Here are some examples:

Zero gap

300px wide outer grid.
Outer grid gap: 50px
grid-template-columns: 100px 1fr;
Subgrid gap: 0;

1fr = 300 - 100 - 50 = 150px
Subgrid left cell = 100px + (50/2) = 125px
subgrid right cell = 300 - 100 - (50/2) = 175px

subgrid gap diagram with zero gap

Smaller gap

Same thing but this time with a subgrid gap of 25
Subgrid left cell = 100px + (50/2) - (25/2) = 112.5px
subgrid right cell = 300 - 100 - (50/2) - (25/2) = 162.5px

subgrid gap diagram with smaller gap

Larger gap

And to demonstrate how it would work using a gap wider than the original gap (a subgrid gap of 75px)
Subgrid left cell = 100px + (50/2) - (75/2) = 87.5px
subgrid right cell = 300 - 100 - (50/2) - (75/2) = 137.5px

subgrid gap diagram with larger gap

Did that clear things up at all?

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Feb 9, 2018

I've cleaned up my comment and added diagrams now. Sorry about the hasty comments earlier.

@keithjgrant

This comment has been minimized.

Copy link
Contributor

keithjgrant commented Feb 9, 2018

I believe the desired effect (from Rachel’s post) could be achieved if different grid-gap values could be assigned between certain columns/rows. Adding that ability might make for a less complex solution…?

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Feb 9, 2018

different grid-gap values could be assigned between certain columns/rows.

Not a bad idea and it might solve other use cases we don't know about yet.

So as in something like this?

grid-column-gap: 20px;
grid-row-gap: repeat(3, 0px) 20px;

The gap would repeat the row-gap pattern over and over like how grid-auto-rows works.

That would work to solve the use case. It also avoids the issue of subgrid having differently sized columns/rows to the main grid.

The problem comes in when we try to use the shortened version of the syntax.

/*
  This syntax currently sets row-gap to 20px
  and column-gap to 10px
*/

grid-gap: 20px 10px;

Notice that it uses a space to seperate the 2 values?

I think what we could do to get around that problem is to make this syntax also valid:

/*
  This syntax could be introduced to 
  set row-gap to 20px and column-gap to 10px
*/

grid-gap: 20px / 10px;

That way we could do this for the shortened syntax:

grid-gap: repeat(3, 0px) 20px / 20px;
@keithjgrant

This comment has been minimized.

Copy link
Contributor

keithjgrant commented Mar 14, 2018

I’ve been thinking about this, and we might not necessarily need the variable grid gap. The grid gap is effectively just another grid track. The example Rachel gives could be achievable by removing the grid gap and instead adding in 20px grid tracks that remain empty.

This does make using auto-placement algorithm tricky though. I tried something like this here, with named grid lines by declaring grid-template-columns: repeat(3, [col] 200px 20px);. But the grid items all align to the first of the [col] grid lines, since you have to specify grid-column-start: col 2 to align to the second [col] grid line. It gets even more complex with auto-fit or auto-fill.

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Mar 14, 2018

@keithjgrant take a look at my last comment.

Having to creating seperate tracks for the gaps isn't a good solution due to auto-placement.

Making it possible to define different gap sizes on different rows and columns is a much more plausible solution. It only requires a very minor tweak to the grid-gap syntax to make it work. I explain more in that comment.

I think that is my preferred solution now.

@MatsPalmgren

This comment has been minimized.

Copy link

MatsPalmgren commented Apr 21, 2018

It might be possible to solve this by introducing a track alignment step for subgridded axes. Currently, this doesn't occur since a subgrid doesn't do any track sizing/alignment of its own in a subgridded axis. If we do the alignment part though then the author can control the subgrid layout using align-/justify-content and align-/justify-self on the subgrid. I think it's important that tweaking the track sizes in the subgrid like this doesn't feedback into the TSA run by the parent grid though, or we'll get bad circular dependencies. So with that caveat, I implemented this in my subgrid prototype and it seems to work well. The parent grid-gap is still reflected in the parent grid, so the author would need to account for that. So, for example, this is what @rachelandrew's subgrid example looks like with grid-gap:20px in the parent grid and align-content:start; align-self:start; grid-gap:0 in the subgrid:
rachel_andrew_subgrid_example-no-subgrid-grid-gap
Note that the gap between the two rows of subgrids is 80px (60px since the subgrid now doesn't fill up the extent of the four tracks it spans + 20px from a parent row gap there). Changing the grid-gap in the parent to grid-gap:5px 20px would give the desired 20px distance between the rows. Or, the author could use this excess space to do fun stuff like:
rachel_andrew_subgrid_example-no-subgrid-grid-gap-align-self-end
(by adding the rule: .card:nth-child(2n+1) { align-self: end; })

For this to happen the subgrid spec needs to remove bullet 'e' (and 'g' and 'h' but I think I've already requested that elsewhere).

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Apr 22, 2018

Thanks @MatsPalmgren for attempting to implement customisable grid-gap on subgrids :)

I like the idea of being able to alter the alignments of the subgrid items however your implementation is far too unintuitive for me to endorse it.

If I set grid-gap: 20px on the parent then the vertical spacing between the outer grid items should remain visually at 20px regardless of what I set the sub-grid grid-gap to.

Is there a way for the algorithm to recognise that this gap will appear and compensate for it accordingly?

@MatsPalmgren

This comment has been minimized.

Copy link

MatsPalmgren commented Apr 22, 2018

It might seem intuitive that subgrid gaps should trump the parent grid gaps in the example above, but I suspect that's mostly because the parent grid has identically styled subgrids in those rows. In the general case you might have plain items too, and subgrids with different grid-gap values, and subgrids that only partly span the same tracks, and nested subgrids etc. Then it becomes a lot less clear what would be an intuitive gap. As a simple example, why should the subgrid's grid-row-gap:0 squash the gaps between the outer items here?:
rachel_andrew_subgrid_example-outer-items
It seems to me there might be cases where you'd want them intact, but still have zero gaps in the subgrid (as shown).

It might be possible to implement some "gap negotiation" step in the TSA, to take subgrid gaps into account, but this complicates implementations somewhat because they would have to support non-uniform gap values internally. In that case, I'd suggest adding a new opt-in syntax for these "soft" negotiated values to enable a subgrid to still be able to trump the parent gaps locally without propagating that value upwards (and similarly for the parent: to ignore any values from subgrid descendants). Something like minmax(min-value[, max-value]) perhaps?

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Apr 22, 2018

Ahh ok, your use-case shows why the multiple gap recommendation I made earlier wouldn't work.

What is the difficulty you see in implementing the original recommendation I made? Take a look at the comment I made above with all the pretty diagrams in it. The grid-gaps act more like borders with box-sizing set to border-box.

The algorithm for the outer grid could still treat the main grid spacing as columns but on the sub-grid, it could treat the gaps like borders. Or maybe it might be easier to adjust the algorithm to treat all gaps like borders for both the outer and sub grid cells?

@MatsPalmgren

This comment has been minimized.

Copy link

MatsPalmgren commented Apr 22, 2018

Well, that's the layout you'd get by default with my proposal. align-content stretches by default, so if you just specify grid-row-gap:0 on the subgrid, this is what you'd get:
rachel_andrew_subgrid_example-outer-items-gap-0-stretch

The problem with that is that the subgrid tracks are now stretched to fill that 60px which might be undesirable, which is why I suggest we enable the author to specify the behavior using align-content/self - so you can "pack" the subgrid with align-content:start for example. But then it might also be desirable to pack the outer grid, for those tracks, to get rid of that 60px entirely, which is what my "gap negotiation" discussed. I thought you asked for this outer packing to occur automatically in your later comment, but I guess I misunderstood.

@MatsPalmgren

This comment has been minimized.

Copy link

MatsPalmgren commented Apr 23, 2018

Actually, align-content:stretch doesn't distribute the space quite as @Dan503 suggested above. With an excess 60px and four tracks it simply grows each one 60px/4. To meet the middle of the gaps though, you'd want to grow the tracks 10px, 20px, 20px, 10px respectively. We would need a new <content-distribution> value for this case, say align-content: meet.

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Apr 24, 2018

Yeah I noticed the lines weren't quite lining up properly in your screenshot. I wasn't sure if maybe it was just a mock up. I'm guessing we would also need a justify-content: meet value as well to make sub-grid columns behave in the same way.

I'm just curious, what currently happens with your algorithm if the gap size on the sub-grid is larger than the gap size of the parent grid?

Does it act similarly to what I suggested in the diagrams or does it increase the outer grid gap spacing? The outer grid-gap spacing shouldn't be affected by the sub-grid spacing.

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Apr 24, 2018

I thought you asked for this outer packing to occur automatically in your later comment, but I guess I misunderstood.

It was this image example you provided that scared me:

rachel andrew subgrid example no subgrid grid-gap

The extra large gap in the middle shouldn't be that large by default. It should be the same size as the gaps between the parent grid columns.

@MatsPalmgren

This comment has been minimized.

Copy link

MatsPalmgren commented Apr 24, 2018

Not a mockup, these are screenshots of my prototype subgrid implementation in Firefox.

I'm just curious, what currently happens with your algorithm if the gap size on the sub-grid is larger than the gap size of the parent grid?

The subgrid never shrink the track sizes. Note that stretch never shrinks tracks in ordinary grids either; instead it causes fallback behavior (i.e. you can then use *-self to align the subgrid as a whole within the content area). So I tend to think meet should behave the same. I wrote up some more details about it in issue #2610. I don't see a use case for shrinking the tracks given that the purpose of the subgrid is to let its items contribute to the track sizes, so it seems logical to have the same content-distribution behavior in a subgrid.

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Apr 25, 2018

So if someone were to set a 10px grid-gap on the parent grid but set a 20px grid-gap on the subgrid, what would happen?

Does the sub-grid max out at whatever the parent grid-gap is (ie. It displays as 10px even though it was explicitly set to 20px)?

Or does the sub-grid still honour the 20px sub-grid gap? If so, how does it align itself in comparison to the parent grid?

@MatsPalmgren

This comment has been minimized.

Copy link

MatsPalmgren commented Apr 25, 2018

It honors the subgrid gap, no tracks are resized, the fallback alignment is used instead.

@Dan503

This comment has been minimized.

Copy link

Dan503 commented Apr 25, 2018

Can you please post a screenshot? I don't understand what "fallback alignment" means in this context. I'm having difficulty visualizing it :(

The link to the spec didn’t really help that much in understanding it :/

@rachelandrew

This comment has been minimized.

Copy link
Contributor

rachelandrew commented Apr 27, 2018

@Dan503 The fallback alignment is detailed in the spec for any alignment method that requires it, so for example with space-between it is start or flex-start, which would come into play if you only had one item so there is nothing to make space between.

@tabatkins

This comment has been minimized.

Copy link
Member

tabatkins commented Apr 30, 2018

I agree with @fantasai - I think the best way to manage this is by accumulating "additional extra margin" (possibly negative margin) on the subgrid's items, if the subgrid has a different grid-gap than the parent grid. We already do this for the subgrid's outer-edge items to account for the subgrid's m/b/p.

This gives us the behavior that subgrid gaps are still centered with the parent grid gaps, which is what @Dan503 wants.

@mrego, just saying "use a grid-gap:0 on the parent, and then use margin on the subgrids to separate them the needed amount" only works if you know exactly how many rows you have (and where each item will be placed), or if you specifically want the "half space on each edge, full space between" pattern. If you want the normal gap behavior of "zero on the edge, full space between", you can't do it with margins if your items are unpredictably spaced or using the implicit grid.

fantasai added a commit that referenced this issue May 8, 2018

[css-grid-2] Define gap handling for subgrids per discussion in #2285.…
… Many thanks to Dan503 (Daniel Tonon) for the illustrations.
@fantasai

This comment has been minimized.

Copy link
Contributor

fantasai commented May 8, 2018

OK, I've checked in commits that specify the method proposed in #2285 (comment) which afaict implements exactly the behavior @Dan503 has requested here.

You can read the new text at https://drafts.csswg.org/css-grid-2/#subgrid-gaps

@Dan503 I hope you don't mind that I stole your examples and diagrams from #2285 (comment) ? :)

@MatsPalmgren This is a different approach than what you have been sketching out here, but we think it better matches author intent.

@fantasai fantasai added the Agenda+ label May 8, 2018

@Dan503

This comment has been minimized.

Copy link

Dan503 commented May 8, 2018

Happy for them to be used, glad they were useful to you @fantasai :)

@fantasai

This comment has been minimized.

Copy link
Contributor

fantasai commented May 8, 2018

@Dan503 They're wonderful, thank you so much. :)

@Dan503

This comment has been minimized.

Copy link

Dan503 commented May 8, 2018

@MatsPalmgren has a point that people will probably want the ability to adjust how the alignment works though.

I can see people wanting to maybe align the sub-grid to align with one side of the outer-grid for example. I'm not exactly sure how that might work syntactically though.

@css-meeting-bot

This comment has been minimized.

Copy link
Member

css-meeting-bot commented May 23, 2018

The Working Group just discussed subgrid and grid-gap, and agreed to the following:

  • RESOLVED: Accept the edits
The full IRC log of that discussion <dael> Topic: subgrid and grid-gap
<Rossen> https://github.com//issues/2285#issuecomment-387255908
<fantasai> https://github.com//issues/2285#issuecomment-387255908
<dael> github: https://github.com//issues/2285
<dael> fantasai: Initially when we created subgrid we said you can't control the gaps in the subgrid. Request was to be able to control. What we're doing is we added text to explain. If the sub grid's gap value is different then parent we add fake margins to the edges of the items adjacent to one of the gaps
<dael> fantasai: We're kind of doing this for outer edges of items on subgrid.
<dael> fantasai: Using the same technique we're handlign the differences in grid gaps. afaict this is the behavior authors want. Allows gap control, simple from impl view.
<fantasai> https://drafts.csswg.org/css-grid-2/#subgrid-gaps
<dael> fantasai: It's checked in and you can read text here ^
<dael> fantasai: This is a question of does it sound good to everyone
<dael> Rossen: I did read this ahead of the call. Doesn't seem difficult to impl. Valid use cases. I support
<dael> Rossen: Other opinions?
<dael> Rossen: Objections to proposed edits?
<dael> RESOLVED: Accept the edits
<Rossen> https://github.com/w3c/csswg-drafts/commit/f33560757fcb0c55b8b6b8e2308eb24a92f1e6dd
<dael> Rossen: These the edits?
<dael> fantasai: Yeah
@Dan503

This comment has been minimized.

Copy link

Dan503 commented May 23, 2018

@fantasai I made a normal version of the diagram so that the normal description in the spec wouldn't look like the odd one out.

subgrid-gap-diagram-normal

Note: There are a couple of mistakes in the editors draft.

if its column-gap were normal:
...without any special adjustment, thus stretching to 175px wide...

It should say 150px wide. 175px wide is the width it would be with zero gap.

if its column-gap were 75px:
...as if it had a -37.5px right margin, thus stretching to 87.5px wide...
...as if it had a -37.5px left margin, thus stretching to 137.5px wide...

These should actually be positive margins of 12.5px. No margin is what you get on normal. Negative margin is what you get if the grid-gap is less than the parent grid-gap. Positive margin is what you get if the grid-gap is greater than the parent grid-gap.

@fantasai

This comment has been minimized.

Copy link
Contributor

fantasai commented Jun 12, 2018

@Dan503 Added in! Also fixed the errors, I clearly wasn't double-checking the math that day. Thanks a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment