Re: [csswg-drafts] [css-nesting] selecting grandparent selector with @nest (#6977)

By my reading of the spec, this construction already has an unambiguous meaning.

```
.a {
  & .b {
    @nest :not(.c)& {
      color: red;
    }
  }
}

/* With explicit `:is` expansion,
the innermost selector would be: */

:not(.c):is(:is(.a) .b) {}

/* reordering pseudo-classes */
:is(:is(.a) .b):not(.c) {}
/* removing redundant inner :is */
:is(.a .b):not(.c) {}
/* I'm pretty sure the remaining :is
is also always redundant. */
.a .b:not(.c) {}
```

I _think_ I got all that right, anyway.

The other case bottoms out, by my understanding, into something vaguely close to the desired output, but much more permissive by matching `:not(.c)` in _any_ ancestor position.

```
.a {
  & .b {
    @nest :not(.c) & {
      color: red;
    }
  }
}

/* expansion of innermost selector */
:not(.c) :is(:is(.a) .b) {}
/* removing inner :is */
:not(.c) :is(.a .b) {}
/* This transformation is probably less
tractable generally, but
distributing
:not(.c) is valid in this case, I think. */
:is(
  :not(.c) .a .b,
  .a:not(.c) .b,
  .a :not(.c) .b
) {}
```

Here is something that simplifies in the desired way, but requires the repeating of the `.a` in the innermost selector.

```
.a {
  & .b {
    @nest .a:not(.c) & 
  }
}

/* expansion of innermost selector */
.a:not(.c) :is(:is(.a) .b) {}
/* removing inner :is */
.a:not(.c) :is(.a .b) {}
/* because .a:not(.c) is more selective than .a */
.a:not(.c) .b {}
```

In this case, `.a` could instead be any single selector, but repeating a gnarly outer selector deeper down is obviously not that good.

This is where I see the semantic and syntactic holes lining up. Since the syntax that motivated this request already has a simple, consistent meaning, we would need new syntax to ease the repetition burden.

I think the direct solution would be a way to refer to outer selectors, for instance allowing `&2`, `&3`, etc to appear in any selector that also includes either a bare `&` or the equivalent `&1`.

Another possibility: Custom selectors would solve the repetition problem generally, at the cost of a little cruft to define the selector name. Being able to place a hypothetical `@custom-selector` inside a declaration block to give a scoped name to `&` would be a delightful trick.

```
.a {
  @custom-selector :--granny &

  & .b {
    @nest --granny:not(.c) & 
  }
}
```

This way, there would be no truly new syntax (just a novel combination of two proposed standards). Parsing custom selectors, I think, doesn't require much more than expanding the syntactic sugar, but there could also be some dark corners there.

At any rate, it's something a preprocessor could support as long as it properly wraps the referent of `&` in `:is` during expansion. It's probably worth seeing if any preprocessors can be configured to perform the necessary transformations correctly; if they follow the spec as it stands, I don't _think_ things would get out of hand.

-- 
GitHub Notification of comment by WCWedin
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/6977#issuecomment-1244905968 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Tuesday, 13 September 2022 05:10:54 UTC