w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.52k stars 672 forks source link

[css-nesting] Allow CSS nesting for inline styles #8752

Open miragecraft opened 1 year ago

miragecraft commented 1 year ago

Whether CSS nesting works for inline styles isn't actually defined in the specs, as far as I can find.

So I was under the assumption that I could do:

<ul style="
   & a {
    font-weight:bold;
    &:link {color:green}
    &:is(:hover, :active) {color:red} 
  }">
  <li><a href="#">Home</a></li>
  <li><a href="#">Blog</a></li>
  <li><a href="#">About</a></li>
 </ul>

And found out that no, it doesn't work.

I'm hoping that this behaviour can be defined at the very least, and allowed if at all possible.

By allowing nesting to work with inline styles, it creates a very useful method to scope CSS styles.

LeaVerou commented 1 year ago

This has been discussed before, though I can't find the issue. The tl;dr was, we agree it's useful, but it's fairly difficult to implement, so it will ship later.

miragecraft commented 1 year ago

Thanks for the information. Good to know that this feature is coming in the future.

myfonj commented 1 year ago

Does it mean it would allow inline style attribute to:

  1. Define dynamic and validation state appearances, like &:hover, &:active, &:invalid for the host element?
  2. Define content of &::before &::after pseudos of the host element?
  3. And (gasp) even affect parents (*:has(>&)) and siblings (& ~ *)?

1:

<button style="&:active { color: red; }">Click for red.</button>

2:

<el style="&::before { content: 'Bang: '; }">❗</el>

3:

<parent>
  Green.
  <el style="
    *:has(>&) { color: green; }
    & + el { color: red; }
  ">(Also green.)</el>
  <el>Red.</el>
</parent>

That would be rad❗


BTW, shouldn't this issue remain opened up until specs are done and linked here?

bramus commented 9 months ago

I don’t think this issue should have been closed. Reopening so that people can find this and participate …

juner commented 7 months ago
<ul style="
 & a {
  font-weight:bold;
  &:link {color:green}
  &:is(:hover, :active) {color:red} 
}">
 <li><a href="#">Home</a></li>
 <li><a href="#">Blog</a></li>
 <li><a href="#">About</a></li>
</ul>

Are you suggesting that you want the html shown above to be equivalent to the html shown below?

<ul>
 <style>
   @scope {
     & a {
       font-weight:bold;
       &:link {color:green}
       &:is(:hover, :active) {color:red} 
     }
   }
 </style>
 <li><a href="#">Home</a></li>
 <li><a href="#">Blog</a></li>
 <li><a href="#">About</a></li>
</ul>

playground

myfonj commented 7 months ago

Yes, presumably it is exactly the equivalent.

The line of thought here is that now the outermost & inside regular style sheet is implicitly bound to the :root element (1), so idea for style attribute to have the & bound to the host element really sounds quite reasonable. Technically it could mean just specifying, that there was implicit & { } wrapping inline style attribute content all the time, just now we can use explicitly.

Equivalence of construct like & { & { & { color: red; }}} and color: red; works, so backwards compatibility with &-less style attribute values is ensured.

(1) see:

<!doctype html><html><head>
<style>
&:is(:root) {
 & > body > p { color: red; }
}
</style></head><body>
<p>I am red. (This works already.)
juner commented 7 months ago

Is it possible that the previous inline-style was interpreted like this...?

<div>
   <span style="color: red">I am red.</span>
</div>

<div>
   <span>I am red.<style>
     @scope { & {
       color: red;
     } }
   </style></span>
</div>

playground

myfonj commented 7 months ago

If I read it correctly then yes: since the style in your sample is inside the <span>, it should not affect its parent, so yes, it should be equivalent of inline style attribute on the <span>. As I understand it that redundant extra & { } wrapper inside the @scope { } should make no difference, so would really be "redundant" in a same way the inline style attribute implicit illustrative wrapper.

Examples in current draft confirm that:

myfonj commented 7 months ago

Interesting question arises whether putting @scope inside style attribute value should be allowed and equivalent of non-scope/nest as well:

<el style="…"></el>
<el style="@scope { … }"></el>
<el style="@scope { & { … } }"></el>
<el style="@scope { @scope { :scope:is(&) { & { … } } } }"></el>

(I see no reason why not, but admittedly it is getting funky.)

juner commented 7 months ago

@myfonj The reason for the redundant selector is that blink(chrome) cannot yet write properties directly to @scope ...

```css /* work */ & { @scope { color:red; } } /* not work */ @scope { color:red; } /* work */ @scope { & { color:red; } } ``` [playground](https://livecodes.io/?x=id/id8ffw6ghkp)
juner commented 7 months ago

@myfonj Can @scope accept declarations without any intermediate structure?

@scope {
   color: red;
}
jogibear9988 commented 6 months ago

As Tailwind is use more, I suggest if inline pseudo classes could be revisited? Found this old proposals: https://www.w3.org/TR/2002/WD-css-style-attr-20020515 https://discourse.wicg.io/t/proposal-expand-inline-style-attributes-to-allow-pseudo-class-element-styling/1812/

LeaVerou commented 6 months ago

Tailwind is also used for inline media queries. Though even if we did allow them, they would not come close to the conciseness of utility classes.

jogibear9988 commented 6 months ago

yeah, but it would be a start. the next step could be to allow also media queries etc in local styles.

But I think for example styling a ":hover" in the local style could be usefull