Skip to content

[css-grid-2] Subsetting grid-template-areas in subgrids #4411

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

Closed
fantasai opened this issue Oct 10, 2019 · 18 comments
Closed

[css-grid-2] Subsetting grid-template-areas in subgrids #4411

fantasai opened this issue Oct 10, 2019 · 18 comments

Comments

@fantasai
Copy link
Collaborator

fantasai commented Oct 10, 2019

Pulling out one of @MatsPalmgren's issues from #2564


@MatsPalmgren wrote:

ISSUE 4: line name matching for grid-template-areas that are (partly) outside of the bounds of the subgrid needs to be defined

The way I solved this is to view the areas themselves as sliced by the subgrid and then generate implicit area names for that slice, for example:

<div style='display:grid; grid-template-areas: "a a a a a a a a a a"'>
  <div style="display:grid; grid:auto/subgrid; grid-column: 6 / span 5">
    <x style="grid-column: a">x</x>
  </div>
</div>

Resolves to 1 / 6, because the subgrid sees a a-start line at its line 1 and a-end at line 11. That is, the areas in ancestor grids that have an edge outside the subgrid generates its corresponding implicit area name at the subgrid edge instead. This matters because for example:

<div style='display:grid; grid-template-areas: "a a a a a a a a a a"'>
  <div style="display:grid; grid:auto/subgrid [a-start] [a-start]; grid-column: 6 / span 5">
    <x style="grid-column: a-start 2">x</x>
  </div>
</div>

Resolves to 2 / 3, because the a-start of the parent grid coincides with the explicit a-start at line 1 in the subgrid.

Note that implicit area names are still generated for all grids though, so for example:

<div style="display:grid; grid-template-areas: '. . . . . . a a a a'">
  <div style="display:grid; grid:auto/subgrid; grid-column:2/-1; grid-template-areas: '. . a'">
    <div style="display:grid; grid:auto/subgrid; grid-column:2/-1; grid-template-areas: '. . a'">
      <div style="display:grid; grid:auto/subgrid; grid-column:2/-1; grid-template-areas: '. . a'">
        <x style="grid-column: a-start 4">x</x>
      </div>
    </div>
  </div>
</div>

have a-start lines at line 1 (from the outermost subgrid), line 2, line 3 (from the innermost subgrid) and line 4 (from the root grid) so a-start 4 is resolved as 4 in this case.


@fantasai replied:

ISSUE 4: This is an interesting case, I hadn't really thought about it. Named areas don't really "exist" in Grid; they're just a shorthand syntax for adding *-start and *-end line names to the grid. (Note that you can use grid-area: a solely by manually adding a-start/a-end lines to the grid, avoiding grid-template-areas entirely.) So I would have expected that we'd just inherit the -start/-end line names that happen to cross into the subgrid, without doing anything special.

If we resolve by simply ignoring the line names outside the subgrid’s spanning area, then the -start/-end lines outside the subgrid area would just get dropped. The item would then position against the subgrid's fake-implicit grid lines, and subsequently get clamped to the actual bounds of the subgrid, yielding the same behavior you propose.


@MatsPalmgren replied:

ISSUE 4: [...] Named areas don't really "exist" in Grid; they're just a shorthand syntax for adding *-start and *-end line names to the grid.

The names in grid-template-areas specifies which tracks are covered by an area, the -start/-end lines are byproduct of that...

(Note that you can use grid-area: a solely by manually adding a-start/a-end lines to the grid, avoiding grid-template-areas entirely.)

Indeed, and in a non-subgrid world I would agree that they are entirely equivalent. However, in a subgrid world, a subgridded axis "shares" the tracks with its parent grid so it seems logical to me that the names in the parent grid-template-areas are shared by the subgrid for the slice of the area that the subgrid covers. Here's a simpler example:

<div style='display:grid; grid-template-areas: "a a a a a"'>
  <div style="display:grid; grid:auto/subgrid; grid-column:2/span 3">
    <x style="grid-column:a-start">x</x>
  </div>
</div>

I think the <x> item should start at line 1 in the subgrid, because the subgrid's first track is in the "a" area (i.e. the second track in the parent grid) and thus it sees an a-start at line 1 since the "a" area, from its perspective, starts there. You're suggesting that since the parent's a-start is outside the subgrid it's invisible, hence it resolves the same as "grid-column:foo" which gives the result 3 / 4, so it doesn't give the same result. It seems we agree that a-start should match the first line in the subgrid though. I just don't understand how you get that result with your explanation. Could you elaborate?

@fantasai
Copy link
Collaborator Author

fantasai commented Oct 10, 2019

I just don't understand how you get that result with your explanation. Could you elaborate?

@MatsPalmgren I think I was misinterpreting the search direction, thought that grid-*-start would look to the implicit lines before line 1 if it did not find the specified named line. It's doesn't seem to be particularly explicit in the Grid spec, but it seems like it would actually only search the implicit lines after the last line, so my suggestion wouldn't work.

I think we have four options here:

  • A) Define that a subgrid subsets its parent grid’s template based on what part of it is covered, and ensures that its edges provide the requisite -start/-end lines at its edges. (This makes templates more of a "thing", rather than a mere translation into line names that can subsequently be forgotten.)
  • B) Define that the grid-*-start property searches the implicit lines before the first line instead of the lines after the last line if a specified line name is missing, similar to how span foo searches in opposite directions based on whether its a grid-*-start or grid-*-end value.
  • C) Define that, while implicit lines have most names in the infinite space of possible names, only lines before the first line also have names ending in -start, and only lines after the last line have names ending in -end.
  • E) Don't handle template subsetting; the cases you describe will be a type of error.

B & C imply changes to Grid Level 1 behavior, but really only to error cases (missing line names).

@mirisuzanne
Copy link
Contributor

I would have expected an A-variation that is still based on line-names rather than tracking areas as a "thing". If parent line names (including *-start, *-end, and arbitrary names) are considered "available" to the subgrid, but clamped to the subgrid edges – that doesn't require tracking the template area, only the lines that are generated. Those line-names would stack-up at the edge of the subgrid if they are defined outside the available space.

I made a pen of the demos above if anyone else finds a visual helpful…

@rachelandrew
Copy link
Contributor

Behavior A makes the most sense to me, it seems easily explained to authors and I think will be logical to anyone encountering grid and subgrid for the first time. If you place something into an area partly covered by a subgrid it then goes into the part that is available, and foo-start and foo-end will then map to the bounds of that area when used to place things in the subgrid.

I've been playing around with a bunch of naming usecases recently and I can't think of good use cases for the other behaviors at the moment. I think template subsetting as described in A could be useful though.

@fantasai
Copy link
Collaborator Author

@rachelandrew A, B, and C will all have that effect. The question is how we want to get there.

@mirisuzanne OK, so that's a new option :) So we've got

  • A) Define that a subgrid subsets its parent grid’s template based on what part of it is covered, and ensures that its edges provide the requisite -start/-end lines at its edges. (This makes templates more of a "thing", rather than a mere translation into line names that can subsequently be forgotten.)
  • B) Define that the grid-*-start property searches the implicit lines before the first line instead of the lines after the last line if a specified line name is missing, similar to how span foo searches in opposite directions based on whether its a grid-*-start or grid-*-end value.
  • C) Define that, while implicit lines have most names in the infinite space of possible names, only lines before the first line also have names ending in -start, and only lines after the last line have names ending in -end.
  • D) Define that all line names from the parent grid that are before the subgrid are assigned to the subgrid's first line, and all line names after the subgrid are assigned to the last line.
  • E) Don't handle template subsetting; the cases you describe will be a type of error.

@rachelandrew
Copy link
Contributor

what I was saying was that I don't see use cases for the other behaviors which seem more complex to me, but maybe they aren't in reality.

@fantasai
Copy link
Collaborator Author

@rachelandrew Well, for the grids that effectively define grid areas using -start/-end lines rather than an ascii template, the other options would let those work equivalently. Which is probably a concrete benefit to B/C/D vs A. (The other one being that templates have up til now been just a convenient way to assign those line names, not an entity of themselves, so would maybe make sense to continue that attitude.)

@mirisuzanne One concern with your approach, suppose the author is repeating the pattern [outer-start] [inner-start] [inner-end] [outer-end] throughout a grid, each set representing a "column" of content. If the subgrid takes up, say, four columns but there are six columns in the parent grid, then the first and last lines of the subgrid gets assigned all four names instead of just [outer-start], which is probably not what we want since the first item positioned to inner-start will start at what the author thinks of as an outer-start line.

@mrego
Copy link
Member

mrego commented Oct 15, 2019

I've been checking this thing and I believe I like C, however I'm worried about the compatibility risk and if we're going to break websites doing this change. Maybe we should add a use counter, to check if people are using random line names to place elements or not.
A safer approach would be go with B, and eventually move to C if the use counter is low.

One thing I don't like about current implementation is that these 2 cases are not identical:

<div style="display: inline-grid; border: solid thick;
            grid-auto-rows: 50px;
            grid-template-columns: repeat(5, 50px);
            grid-template-areas: 'a a a a a';">
  <x style="grid-column: a; background: magenta;">i1</x>
  <div style="display: grid;
              grid: auto / subgrid;
              grid-column: 3 / span 3;">
    <x style="grid-column: a-start; background: cyan;">i2</x>
  </div>
  <div style="display: grid;
              grid: auto / subgrid;
              grid-column: 3 / span 3;">
    <x style="grid-column: a; background: yellow;">i3</x>
  </div>
</div>

<hr>

<div style="display: inline-grid; border: solid thick;
            grid-auto-rows: 50px;
            grid-template-columns: [a-start] repeat(5, 50px) [a-end];">
  <x style="grid-column: a; background: magenta;">i1</x>
  <div style="display: grid;
              grid: auto / subgrid;
              grid-column: 3 / span 3;">
    <x style="grid-column: a-start; background: cyan;">i2</x>
  </div>
  <div style="display: grid;
              grid: auto / subgrid;
              grid-column: 3 / span 3;">
    <x style="grid-column: a; background: yellow;">i3</x>
  </div>
</div>

Output in Firefox nightly 71.0a1

I'd expect both render the same and work, like it happens for the first one, but the 2nd one is doing something different.

@MatsPalmgren
Copy link

@fantasai

A, B, and C will all have that effect.

They behave slightly differently though. For example:

.grid { grid-template-areas: "a a a a a a a a a a"; }
.subgrid { grid-template-columns: subgrid [a-start];  grid-column: 3 / span 5; }
.item { grid-column: a-start 2; }

With A, the subgrid's explicit a-start is the same line as its implicit a-start from the a area, so a-start 2 doesn't match an explicit line and the item ends up in the last track of the subgrid. With B, no explicit line match either but now we match the implicit line before the subgrid, which we'll clamp to line 1 in the subgrid.

B has the effect that for example x 3 can be before x 2, which seems confusing:

grid-template-columns: [x] 0 [x];

C needs to define what a missing -start/-end lines resolves to. The way it works now is that all implicit lines matches all names so there are never any matching errors really (which is an easy and consistent model to understand IMO). What does a-start 30 resolve to in the first example above if lines after the subgrid's last line don't match -start names?

D will also have some surprising effects due to collapsing all names to the edge line. e.g.

.grid { grid-template-columns: [a] 0 [a] 0 [a] 0 [a]; }
.subgrid { grid-template-columns: subgrid;  grid-column: 10 / span 5; }

which is the subgrid is equivalent to subgrid [a] which means a 2 etc will behave strangely. I also don't like that explicit line names outside the subgrid can affect the matching inside the subgrid. Insulating the subgrid from unrelated line name changes seems like a good property to have.

E: I like this option more the more I think about it. It's a very simple model.

(Was D supposed to be what @mirisuzanne suggested? If so, I understood her suggestion differently. She only said that "A-variation that is still based on line-names rather than tracking areas" so I don't think she meant to include all line names (as in D), but only implicit ones associated with the grid-template-areas. I might have misunderstood though.)

@MatsPalmgren
Copy link

MatsPalmgren commented Oct 15, 2019

So, in the order I prefer the alternatives:

  • E: This is a very simple model - it should be easy to implement and teach. It doesn't require changes to Grid 1 and it insulates the subgrid from all line names that are outside its extent.

  • A: (either "area-based", as currently implemented in Gecko, or a more line-based version as @mirisuzanne suggested) This is a somewhat more complicated model, but still fairly simple to implement and teach. It insulates the subgrid from explicit line names in the parent grid that are outside its extent. (EDIT: ... and implicit lines from parent grid-template-areas only affects the subgrid if that area intersects the subgrid.)

  • D: Conceptually a simple model but I think it's a lot harder to implement than it sounds. Also, collapsing all outside names to the subgrid's edges leads to rather weird behavior that doesn't seem very useful. Arbitrary line name changes outside the subgrid can affect matching inside the subgrid which seems undesirable.

  • B and C: These are more complicated models to understand and have weird effects. They also aren't compatible with Grid 1, which is interoperably implemented and shipped by all major browsers for several years (possible web-compat fallout, implementation regressions, etc). I'm fairly strongly opposed to these options since they are invasive and thus disproportionate to solve the problem at hand.

(I'll take a stab at implementing E to see what falls out and report back...)

@MatsPalmgren
Copy link

@mrego Yes, you're making a good observation. We only implemented the matching for implicit line names associated with explicit areas (i.e. grid-template-areas), not for implicit areas in the parent grid. This is indeed slightly asymmetric.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Subsetting grid-template-areas in subgrids.

The full IRC log of that discussion <dael> Topic: Subsetting grid-template-areas in subgrids
<dael> github: https://github.com//issues/4411
<dael> fantasai: Presenting the issue: Mats pointed out don't have way to have subgrid...if you have a grid area that's named with template and a subgrid that partially overlaps it will have only inherited line names. Might have foo-n line in the middle, but foo-start not inside subgrid
<dael> fantasai: If try and place item in slot foo it can't find the start line
<dael> fantasai: Can we get that to fit within the part of the slot where it overlaps
<dael> fantasai: Multiple ways to impl with proposals in issue. One is template areas are handled specially and generate extra line as necessary in order to have both edges represented within the subgrid.
<dael> fantasai: Disadvantage is if you created grid area using lines it doesn't behave the same as with template.
<dael> fantasai: Anthoer proposal was define that if we can't find and foo-start lines or any foo lines in subgrid as searching grid-column-start instead of going to the nth edge of the subgrid we search into previous area
<dael> fantasai: Problem with this is it's a slight change to general way grids work; could be web compat
<dael> fantasai: Another is change search direction only for line names that start with 'start'. Again a behavior change
<dael> fantasai: Last is don't handle template subsetting and you have the case where n line exists but start doesn't
<dael> fantasai: Active discussion in issue, I don't think there's a clear right answer. Easist is we pull the line names and you get weird results if using name from parent template grid.
<dael> AmeliaBR: I don't think anyone will have strong opinions without looking in great details. Are you just letting us know?
<dael> fantasai: Wanted to collect opinions. If no one has anything to add we can come back later
<dael> Rossen_: I think we should continue on GH on this one
<dael> AmeliaBR: Isn't this a bit of a rush b/c FF is shipping?
<dael> fantasai: Yeah, we should aim to figure out in the next week
<dael> Rossen_: Once ew have a proposed solution we can add it.

@astearns astearns removed the Agenda+ label Oct 16, 2019
@MatsPalmgren
Copy link

So, I implemented E and as expected it's fairly straight-forward (in our case just removing the code that currently implements A). I think E can be summarized as: explicit line names in ancestors are visible to the subgrid on the lines it shares with its ancestors; other ancestor line names are invisible.

@tabatkins
Copy link
Member

Ah, so if the subgrid fully overlaps a parent's grid area, the subgrid's children still don't see those lines?

That's a consistent position I can get behind.

@MatsPalmgren
Copy link

MatsPalmgren commented Oct 16, 2019

Right, grid-template-areas creates implicit named lines which (for option E) effectively means it can't affect any subgrids at all. (The subgrid itself can still use grid-template-areas locally for its items of course.)

@Dan503
Copy link

Dan503 commented Oct 17, 2019

Ah, so if the subgrid fully overlaps a parent's grid area, the subgrid's children still don't see those lines?

I think that is unintuitive and not particularly useful.

The way I imagine it working is that the sub-grid kind of crops the parent grid areas.

.parent-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grud-template-areas: "a a a a b";
}

.sub-grid {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 2 / 4;
}

.sub-grid-cell {
  grid-area: a;
}
Parent grid:  |a-start     |             |               |     a-end | b-start  b-end|

Sub grid:     :            |a-start      |          a-end|           :               :

@MatsPalmgren
Copy link

The way I imagine it working is that the sub-grid kind of crops the parent grid areas

FYI, that's basically option A) above or some variation of it.

@tabatkins
Copy link
Member

tabatkins commented Nov 1, 2019

Okay, so I think we've got two consistent proposals I'm happy to live with:

  1. Slightly reify grid-template-areas, and exclude all template-created line names from inheriting into subgrids. (Option E)
    • This means that no parent areas are usable in a subgrid, if they were created by grid-template-areas.
    • If an author manually creates an area by specifying foo-start/end lines in the parent grid, they will inherit in and be usable if both the start and end lines overlap the subgrid; a partially-overlapping area will still give you the broken results that the current spec gives you for all partially-overlapping areas.
  2. Slightly reify grid-template-areas, and add line names of areas that partially overlap the subgrid to the start/end of the subgrid, effectively subsetting the grid area into the subgrid. (Option A)
    • This means that all parent areas are usable in a subgrid.
    • Just like (1), if an author manually creates areas by specifying foo-start/end lines, they'll only be usable if they fully overlap the grid area; they won't get the "subsetting" effect that template-created areas get.

The other proposals, while attractive in some ways, have too many problems to be seriously considered imo. Agenda+ to decide between these two proposals.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Subsetting grid-template-areas in subgrids, and agreed to the following:

  • RESOLVED: Pick option 2 effectively subset the grid area into the subgrid
The full IRC log of that discussion <dael> Topic: Subsetting grid-template-areas in subgrids
<dael> github: https://github.com//issues/4411
<fantasai> https://github.com//issues/4411#issuecomment-548945615
<dael> fantasai: Summary comment^
<dael> fantasai: Two proposals, make grid-template-areas a thing and exclude names from inheriting. Currently grid-templates make start and end and those would not inherit into subgrid
<dael> fantasai: Other option is we take those names and instead of saying don't inherit in, they do inherit in and if there's partial overlap we clip start or end so they exist in the grid and you can position to the overlap
<dael> fantasai: Slight inconsitencies for both. If we exclude then a manually created grid area such as named lines as foo-start I implicitly create foo which I can position into. Kinda works on a subgrid; if both lines overlap. True in both cases
<dael> fantasai: Question is do we want...we didn't want to create inconsisent behavior for tempaltes. Want to say either set to part it overlaps or exclude all lines. Those are the two options.
<dael> fantasai: Would like to hear from other preference
<dael> Rossen_: Prefer second option.
<fantasai> A) Exclude parent template and its implicit line names from subgrid
<fantasai> B) Subset parent template to the part where it overlaps the subgrid, allowing it to be usable
<dael> Rossen_: Having the grid-template-area lines not available from subgrid is quite weird given that rows and columns are available
<dael> Rossen_: I would lean toward the second solution if we have to pick from these two
<dael> dbaron: Looks like Mats preference was first, but seems reasonably okay with either. Seems he had impl of 2nd and changed to 1st.
<dael> fantasai: He originally wanted B, then did A when we weren't sure
<dael> Rossen_: dbaron do you know why he switched?
<dael> rego: It was not impl in all cases. I had example in issue that was different in 2 cases where should be same. He didn't have whole impl. I think he did the simpliest thing
<fantasai> Mats's comments https://github.com//issues/4411#issuecomment-542292465
<dael> Rossen_: If we go with option B (the second option)
<dael> Rossen_: Would that be okay dbaron if you're representing Mats?
<dael> dbaron: I'm only reading his comments in issue
<dael> jensimmons: Still trying to wrap my head around. Seems like AmeliaBR and rachelandrew were advocating for A
<dael> Rossen_: A in TabAtkins summary is option 2
<AmeliaBR> s/AmeliaBR/Miriam Suzanne/
<rachelandrew> option 2 for me (don't think my mic is working)
<dael> fantasai: rego I think case with a difference is case of explicit line names creating implicit area.
<dael> fantasai: TabAtkins and I discussed and concluded there wasn't a good way to make that work. Would require changes to how line names were handled. Couldn't figure out how to not cause changes to normal grid
<dael> fantasai: Concluded line names from tempate are special and special for subgrids but explicit line names don't. Which means you can handle hte partial overlap nicely for template areas, but not for area with explicit names
<dael> rego: So original impl from Mats is final?
<dael> fantasai: Yeah. Either way the line names created by template area need to be special so we either notice they're excluded or clamped for partial overlaps. Seems second is more useful
<dael> rego: Still don't like difference in the example. I understand it's useful so maybe it's good enough. I think the difference can create confusion.
<dael> fantasai: Ideally we would solve both, but didn't find a good way.
<fantasai> rego, see https://github.com//issues/4411#issuecomment-542288855 for problems with the other options
<dael> Rossen_: Not hearing strong opinions, but more people toward option 2
<dael> Rossen_: Objections to resolving on "Subset parent template to the part where it overlaps the subgrid, allowing it to be usable" unless there's additional comments
<fantasai> Example of option 2 - https://github.com//issues/4411#issuecomment-543174237
<dael> Rossen_: Objections to Option 2: Subset parent template to the part where it overlaps the subgrid, allowing it to be usable ?
<dael> RESOLVED: Pick option 2 effectively subset the grid area into the subgrid

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

No branches or pull requests

9 participants