[csswg-drafts] [css-grid-2] resolving line names in subgrids

MatsPalmgren has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-grid-2] resolving line names in subgrids ==

I figured it might be useful to provide some details on how the nested line name resolution works for subgrids in the prototype I implemented.  Hopefully it can illuminate the issues and provide a starting point for a discussion on what the spec should say on the matter.  (CAVEAT: bare in mind that for this prototype I intentionally implemented what required the least amount of work while still giving somewhat reasonable results.  "Least amount of work" might be different for other UA vendors. I also haven't thought very deep about "does this make sense for authors" :-))

There are two ways to add local line names to a subgrid:
1. using the `subgrid <line-name-list>?` syntax in `grid-template-rows/columns`,
   where `<line-name-list>` expands to:
   `<line-name-list> = [ <line-names> | repeat([ <positive-integer> | auto-fill ], <line-names>) ]+`
   `auto-fill` works similarly to how it works for tracks, except here we fill the extent of the grid rather than a target layout size.
2. `grid-template-areas`

ISSUE 1: the first thing that needs to be addressed is how implicit lines in ancestor grids match line names.  Grid 1 has this rule: ["all implicit grid lines are assumed to have that name..."](https://drafts.csswg.org/css-grid/#ref-for-implicit-grid-lines) which doesn't work very well when looking up names from a descendant subgrid.  For example:
```html
<div style="display:grid">
  <div style="display:grid; grid:auto/subgrid [] [] [] [b]; grid-column:span 10;">
    <x style="grid-column: 1 / b">x</x>
  </div>
</div>
```
The outer grid has 10 implicit tracks with [implicit grid lines](https://drafts.csswg.org/css-grid/#implicit-grid-lines) between them.  So using that rule, line 2 in the outer grid would match `b`, which doesn't seem desirable.  So the subgrid spec needs to explicitly override that rule so that the local `b` line matches above.

ISSUE 2: since subgrids don't have implicit tracks, and thus there are no implicit grid lines that would match line names that otherwise have no match, we need to define how those names are resolved.

Using the example above, how should a subgrid item with `grid-column: foo / span 4` be resolved?  The way I handle it internally is to pretend that there are in fact implicit grid lines, and then simply clamp the result afterwords.  This was the simplest to implement because it allowed me to re-use the existing line name resolution code as is for the most part.  So first we resolve `foo` to 12, then clamp that to 11, then span 4 from there to 15, then clamp that to 11, then enforce a minimum span 1, to get the final result 10 / 11 (placing it in the last subgrid track).  For `grid-column: span bar 2 / foo 3` we resolve to `foo 3` to 14, then clamp that to 11, then search start-wards for two matching `bar` lines from there, which results in -1 (the second "implicit line" on the start side) which is then clamped to 1, so this item spans the entire subgrid (1 / 11).

ISSUE 3: explicit line names in outer grids that are outside the bounds of the subgrid needs to be defined how/if they match.

I solved this case similarly to the above, so for example:

```html
<div style="display:grid; grid: auto / repeat(20, [a] 50px) [a]">
  <div style="display:grid; grid:auto/subgrid; grid-column: span 10">
    <x style="grid-column: span a / a 18">x</x>
  </div>
</div>
```
we first resolve `a 18` to 18 which is then clamped to 11, then we resolve `span a` start-wards from there, matching line 10.  This however:

```html
<div style="display:grid; grid: auto / repeat(10, 50px) repeat(10, [a] 50px) [a]">
  <div style="display:grid; grid:auto/subgrid; grid-column: span 10">
    <x style="grid-column: span a / a 8">x</x>
  </div>
</div>
```
resolves `a 8` to 18, which is clamped to 11, but since there are no matches for `a` start-wards from 11 it matches the first "implicit" line on the start side, so the final result is 1 / 11.


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](https://drafts.csswg.org/css-grid/#implicit-named-line) for that slice, for example:

```html
<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:

```html
<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:

```html
<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.

ISSUE 5: there is an order-dependent rule for resolving plain [`<custom-ident>`](https://drafts.csswg.org/css-grid/#grid-placement-slot) which is ambiguous when the matching is nested

I solved it by recursing on all nested areas first, and only if none of them have a matching area name  we treat it as `<custom-ident> 1`.  So here for example,

```html
<div style='display:grid; grid-template-areas: ". . . . a"'>
  <div style="display:grid; grid:auto/subgrid [] [a-start]; grid-column: span 10">
    <x style="grid-column: a">x</x>
  </div>
</div>
```

`a` matches the explicit `a-start` line because there exists an area named `a`, so the result is 2 / 6.

ISSUE 6: the spec needs to define where implicit area line names occurs when the relevant grid axes have opposite progression directions

For example:

```html
<div style='display:grid; grid-template-areas: ". a a . ."'>
  <div style="display:grid; grid:auto/subgrid; grid-column: span 10; direction: rtl">
    <x style="grid-column: a-start">x</x>
  </div>
```

I implemented this by matching all names as viewed _from the subgrid's perspective_, so the implicit `a-start` associated with the `a` area occurs at the right side when resolving names within the subgrid (and vice versa for -end names).  So the item above is placed at 8 / 9 (which is 3 / 4 in the outer grid).  I think this makes sense if you view the areas as areas and the associated implicit line names occurs as viewed from the item we're resolving names for.

ISSUE 7: local names within the subgrid itself may be outside the subgrid bounds - the spec needs to define how these are handled.  For example:

```html
<div style='display:grid'>
  <div style="display:grid; grid:auto/subgrid [] [a] [] [a] [a] [a]; grid-column: span 2">
    <x style="grid-column: a -1">x</x>
  </div>
</div>
```

resolves to 2 / 3, because searching from the end starts at the end of the grid (line 3), so the trailing `[a] `s are disregarded (just like names outside of the subgrid bounds in ancestors are).  Ditto for:

```html
<div style="display:grid">
  <div style="display:grid; grid:auto/subgrid; grid-template-areas: '. a a a a'; grid-column: span 2">
    <x style="grid-column: a-end -1">x</x>
  </div>
</div>
```

This also resolves to 2 / 3.

Other than that it follows how line name resolution in general works in Grid 1.

While the above may sound complex and thus hard to implement, it actually was fairly straight-forward. Pretty much all existing line name resolution code can be used intact. I only needed to splice in a recursion step in a couple of places, and change existing clamping code to clamp to the subgrid bounds instead of a min/max constant.

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/2564 using your GitHub account

Received on Friday, 13 April 2018 22:26:53 UTC