[csswg-drafts] [css-nesting-1] nesting limited to conditional styling of the current element (another proposal) (#8166)

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

== [css-nesting-1] nesting limited to conditional styling of the current element (another proposal) ==
The points by @mirisuzanne about [the overlap between `@scope` and nesting](https://github.com/w3c/csswg-drafts/issues/7970#issuecomment-1332731115) made me consider another possible direction for nesting.

All current proposal are based on what is done in preprocessors and try to make some version of that work in a browser context.

The feature in preprocessors can be roughly split in these groups :
1. templating to construct BEM style selectors
2. grouping styles for different elements but all part of the same component
3. grouping conditional styles for the same element
4. side effects of the lax syntax in preprocessors

## 1. templating to construct BEM style selectors

Examples :
- `&__element`
- `&--modifier`

This is not part of any of the proposals because it can not (and should not) be implemented.
Authors however use this a lot.

The underlying need is that `@scope` doesn't exist (yet) and that BEM and friends are popular ways to style a component without leaking style to other parts of the document.

`&` templating reduces the amount of writing for authors.

_I however think this could remain a preprocessor feature.
That it can not be implemented in browsers doesn't mean that authors are not allowed to have a tool to help them write repeated bits in selectors._

## 2. grouping styles for different elements but all part of the same component

Example :

```css
.my-component {
  display: flex;
  gap: 3rem;
  margin: 2rem;


  .column {
    width: 50px;

    &.column--left {
      text-align: right;
    }

    &.column--right {
      text-align: left;
    }
  }
}
```

This source code is still flawed and authors will still need to use things like BEM because the html might look like this :

```html
<div class="my-component">
  ...
    <div class="column">
      ...
        <div class="other-component">
          ...
            <div class="column">
```

The second `.column` is completely unrelated to `.my-component` but it will still match `.my-component .column`.

`@scope` solves this and removes the need for BEM methodologies.

## 3. grouping conditional styles for the same element

Example :

```css
.element {
  color: blue;

  &:hover {
    color: pink;
  }

  &:has(img) {
    color: cyan;
  }

  &.element--red {
    color: red;
  }

  @media (prefers-color-scheme: dark) {
    color: yellow;
  }

  @supports (color: oklch(...)) {
    color: oklch(...);
  }
}
```

This is the one thing where I think nesting truly shines and it is something that isn't made obsolete by `@scope`.


## 4. side effects of the lax syntax in preprocessors

Examples :

```css
.element {
  & + .bar {
    /* writing CSS inside `.element` but the matched element is a sibling */
  }
}
```

```css
.element {
  :not(&) {
    /* writing CSS inside `.element` but the matched elements are everything except `.element` */
  }
}
```

I am not convinced these types of selectors are needed.

I am sure that someone will have found a use for them, but are they really needed and do they really help?

-----------------

This makes me wonder how nesting could look like if it had never existing in preprocessors and if we had `@scope` in all browsers today.

Would this be sufficient?

- only nest conditional at rules
- selectors in nested rules can only be compound selectors containing only pseudo selectors
- `&` doesn't exist
- `@nest` doesn't exist

In other words, nesting is only a mechanic to "filter" the elements matched in the parent block.

- it is really simple to learn, both syntactically and which elements will match.
- it is consistent
- it is expressive

```css
@scope (.my-component) {
  :scope {
    /* declarations */

    :hover {}

    @media (min-width: 300px) {}
  }
  
  .element {
    /* declarations */

    :focus {}

    :is([data-theme=red]) {}

    :has(img) {}
  }
}
```

equivalent to :

```css
@scope (.my-component) {
  :scope {
    /* declarations */
  }

  :scope:hover {}

  @media (min-width: 300px) {
    :scope {}
  }
  
  .element {
    /* declarations */
  }

  .element:focus {}

  .element:is([data-theme=red]) {}

  .element:has(img) {}
}
```

The downside of anything in this direction is that authors will dislike it today.
`@scope` must have been widely adopted before a version of nesting with these limitation can be useful.

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


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

Received on Thursday, 1 December 2022 07:33:56 UTC