Skip to content

[css-nesting-1] Wrapping parent selectors with :is() introduces a host of problems #9492

Open
@LeaVerou

Description

@LeaVerou

Opening per action item in today’s telcon ( #8738 (comment) )

Problem

We currently desugar every nested rule using :is(), even when it’s completely redundant. E.g. this:

.foo, #bar {
	& {
		color: red;
	}
}

apparently becomes:

:is(.foo, #bar) {
	color: red;
}

This is not only redundant, it actually has observable side effects: since :is() has a flat specificity equal to the specificity of its argument with the highest specificity, the second rule is not equivalent to the first.

But even worse, because :is() cannot do pseudo-elements, it means this doesn’t work at all:

.foo::before {
	padding: 1em;
	@media (width < 500px) {
		padding: .5em;
	}
}

It would be rewritten like:

.foo::before {
	padding: 1em;
}

@media (width < 500px) {
	:is(.foo::before) {
		padding: .5em;
	}
}

which is invalid.

It also means we cannot fix #8738 by wrapping bare declarations after rules in & {} because in pseudo-elements they could be ignored.

Proposed solution

Edit: I'm not in favor of this any more, see #9492 (comment)

& {} should have no observable side effects. There is never a case where & needs :is() to be rewritten, so adding it not only introduces the problems discussed above, but is entirely redundant.

So a quick fix to the pressing issues could be to simply special case &.

Later down the line, we may want to consider expanding the set of cases that don’t require :is() because there is no danger of combinatorial explosion. From a quick call with @fantasai it seems to us that e.g. cases where there are only simple selectors all the way up would not need :is(), but more research is needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions