csscss-selectorscss-parsing

Why do CSS comma separated selectors break entire rule when one part is unknown?


Explaining the issue:

So if you have a CSS Rule that looks something like this:

h1, h1 a:hover {
  color: blue;
}

It works fine, the example might ne be the best from a usability point of view, but it works. (And it works to demonstrate the issue ...)

But if you add a separated with a comma (,) that the browser doesn't understand, the hole rule is ignored.

 h1, h1 a:hover, h1:focus-within {
    color: blue;
 }

Browser that don't understand the :focus-within pseudo-class will ignore the entire rule. That means even the h1 wont get the specified rule.


Further wondering why it is the way it is:

Don't get me wrong. Ignoring things that they don't know is a very powerful feature in CSS!

But why isn't it designed in a way that only the unknown part is ignored and all the other selectors still work as expected?

Personally I stumble upon this problem very rarely, and I've accepted the fact that one wrong thing in the selector breaks the entire rule. But its hard to explain why a bad declaration or property causes only the specific line to be ignored, while anything unknown in the selectors breaks the entire block.

It feels like I am missing something, so if there is a good explanation let me know and thanks for doing so.


Unsatisfying Solution:

Of course the workaround would be to separated the "dangerous" parts of the selector into new rules like so:

h1, h1 a:hover {
    color: blue;
}
h1:focus-within {
    color: blue;
}

But that feels bad. (Due to "unnecessary" duplication)

Just wanted to put it out here.


Solution

  • It turns out this is actually intentional and defined in Selectors Level 3 (emphasis by me):

    If just one of these selectors were invalid, the entire group of selectors would be invalid. This would invalidate the rule for all three heading elements, whereas in the former case only one of the three individual heading rules would be invalidated.

    Invalid CSS example:

    h1 { font-family: sans-serif }
    h2..foo { font-family: sans-serif }
    h3 { font-family: sans-serif }
    

    is not equivalent to:

    h1, h2..foo, h3 { font-family: sans-serif }
    

    because the above selector (h1, h2..foo, h3) is entirely invalid and the entire style rule is dropped. (When the selectors are not grouped, only the rule for h2..foo is dropped.)


    CSS 2 didn't specify what to do when one selector was wrong. In fact the W3C spec states that the condensed form is equivalent to the written out version:

    In this example, we condense three rules with identical declarations into one. Thus,

    h1 { font-family: sans-serif }
    h2 { font-family: sans-serif }
    h3 { font-family: sans-serif }
    

    is equivalent to:

    h1, h2, h3 { font-family: sans-serif }
    

    EDIT: (thx @BoltClock):

    CSS 2.1 does specify the behavior and it is the same as with CSS3:

    (...) since the "&" is not a valid token in a CSS 2.1 selector, a CSS 2.1 user agent must ignore the whole second line.