Add a rule to disallow unmatched pseudo-elements in (desugared) selectors
What is the problem you're trying to solve?
It's invalid to use native css nesting under pseudo-elements, because nesting desugars to :is() and :is() can't select pseudo-elements. It'd be nice to have a stylelint rule to ensure this type of nesting isn't accidentally introduced.
For example, this isn't valid:
.something::before {
color: blue;
.parent:hover & {
color: red;
}
}
/* becomes .parent:hover :is(.something::before), which is discarded by the browser */
Instead, it would have to be written as
.something::before {
color: blue;
}
.parent:hover .something::before {
color: red;
}
However, nesting media queries is valid (as long as there aren't any further nested selectors within):
.something::before {
color: blue;
@media (min-width: 600px) {
color: red;
}
}
Relevant links:
- Codepen demo
- https://github.com/w3c/csswg-drafts/issues/9492#issuecomment-2219724141
- https://github.com/w3c/csswg-drafts/issues/9702
- https://github.com/w3c/csswg-drafts/issues/2284#issuecomment-363957055
What solution would you like to see?
A new rule that disallows this type of nesting. Autofixing isn't necessary, although probably is possible in simple cases.
@bschlenk Thanks for the request and for using the template.
It does sound like a good candidate for a rule, and similar to our existing no-invalid and no-unmatchable one.
It's a knotty one that we'll need to define the scope of.
Do we think the rule should catch both :is() pseudo-classes that are:
- authored by hand, e.g.
:is(a::before) - desugarred from nesting, e.g.
a::before { b & {} }
For the latter, we can likely use the spec-based nesting resolving that we've experimented with in https://github.com/stylelint/stylelint/pull/7496.
Do you know if it's the same limitation for the other logical combination pseudo-classes, like :where() and :not(), and what other psuedo-elements can't be matched, e.g. ::part, ::marker and so on?