w3c / csswg-drafts

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

[css-nesting-1] Ambiguity of specificity when no nesting selector is used #9069

Open keithjgrant opened 1 year ago

keithjgrant commented 1 year ago

The specification discusses specificity under the section on the nesting selector (&):

The specificity of the nesting selector is equal to the largest specificity among the complex selectors in the parent style rule’s selector list (identical to the behavior of :is()).

However, it doesn't seem to directly address specificity for nested selectors that have multiple parent selectors but do not use &.

.foo,
#foo {
  .bar { ... }
}

Is the nested selector here also equivalent to :is(.foo, #foo) .bar? (or, in other words, is a leading & implicit in this example?)

The current implementations in both Chrome and Safari seem to interpret it that way (demo), and I think this probably makes sense from an implementation standpoint, but I'm having trouble finding something concrete in the spec that states this one way or the other.

plinss commented 1 year ago

As an author, I’d expect that to be equivalent to two rules that cascade independently with different specificity.

.foo .bar { … }
#foo .bar { … }
tabatkins commented 1 year ago

Yeah, if the nesting selector is implied, it should still have an effect on specificity, same as if it was written explicitly. I'll fix the spec. (This matches the serialization behavior we decided on last week.)

@plinss We decided against that behavior in :is() because it drastically complicates the implementation - you have to track which virtual selector was matched (where the number of virtual selectors are multiplicative in the number of :is() selectors. The effect with Nesting is identical, so we went with identical behavior. (This does differ from preprocessors that decompose nested selectors directly, but we fundamentally can't match that without running into this explosion/complexity issue.)

plinss commented 1 year ago

Yeah, but if an author writes:

.foo .bar,
#foo .bar { ... }

They get the equivalent behavior of:

.foo .bar { ... }
#foo .bar { ... }

right? e.g. two rules with different specificity that cascade independently

If

.foo,
#bar {
  .bar { ... }
}

behaves like one rule with a single specificity, then this is an author foot-gun and will cause all sorts of cascading bugs, especially when people refactor existing stylesheets in to nested ones.

I understand it complicates the implementation, but the behavior is not identical and author needs win over implementer needs.

Discuss this at the F2F? (and maybe this needs to get moved into a new issue)