11

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.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Type-Style
  • 1,791
  • 1
  • 16
  • 35
  • 1
    Is `focus-whitin` misspelled intentionally? – Hubert Grzeskowiak Dec 20 '16 at 16:16
  • @HubertGrzeskowiak, read the entire question – Dekel Dec 20 '16 at 16:16
  • 1
    @HubertGrzeskowiak, good point. Nope let me correct that. – Type-Style Dec 20 '16 at 16:16
  • That's why I use all the time this website: `http://caniuse.com/` if I see is not compatible with most of navigators I just make a separated selector for it. – Troyer Dec 20 '16 at 16:17
  • @Troyer that's a good practice, of course, but doesn't answer the question why a browser might ignore the whole rule. – Hubert Grzeskowiak Dec 20 '16 at 16:20
  • Interesting case. Great question! It's the first time I notice this. I just verified that behavior is identical for both Firefox & Chrome, and it applies only to pseudo-selectors [**as far as I can tell**](https://jsfiddle.net/dx5n8djo/1/) – John Slegers Dec 20 '16 at 16:21
  • @JohnSlegers I think this applies to everything that is unclear to the browser. But it is the way it should be for some reason. – Type-Style Dec 20 '16 at 16:25
  • 2
    Unless someone has a reference to the discussion when that part of the spec was being written, I don't think any answer to this can be anything other than opinion. – Quentin Dec 20 '16 at 16:25
  • 1
    The idea might be consistency: I want to mark all the same things red. If the browser doesn't understand part of the selector I don't do half. Other might be that they anticipated future updates to the selector making it possible to do an intersection instead of a sum, there for too much style would be applied – Joel Harkes Dec 20 '16 at 16:26
  • Article with the specs: https://www.w3.org/TR/2013/WD-css-syntax-3-20131105/ – Joel Harkes Dec 20 '16 at 16:28
  • @ILoveCSS do you know about any change to that in CSS Selector Level 4? – Type-Style Dec 20 '16 at 16:28
  • The general direction is far more intellegent CSS - http://css4.rocks/selectors-level-4/matches-pseudo-class.php –  Dec 20 '16 at 16:33
  • @Quentin: I've marked the question as a duplicate. You'll find some references in my answer there. – BoltClock Dec 20 '16 at 16:34
  • @BoltClock way to net yourself more votes... :P – canon Dec 20 '16 at 16:38
  • @John Slegers: Obviously, since type, id, class and attribute selectors can have arbitrary names. – BoltClock Dec 20 '16 at 16:40
  • Actually, and I'll let the asker decide, is [this](http://stackoverflow.com/questions/38856208/what-happens-when-the-browser-doesnt-support-a-css-pseudo-class) a better duplicate? The one I marked discusses in general why bad selectors invalidate entire rulesets; that one discusses bad selectors vs selectors that *look* well-formed but are unsupported. – BoltClock Dec 20 '16 at 16:41
  • 2
    @I Love CSS: Not sure how :matches() is relevant here. The question is about error handling wrt bad selectors, the rules of which are unchanged in selectors-4. – BoltClock Dec 20 '16 at 16:49
  • @BoltClock You're probably right and I just misunderstood. My understanding was that an error would be contained with this new way of writing it. Sort of like how `background: black ; text-zzise: 200px ; color:white` would still paint white text on a black background even though there is a typo in the text-size property in between them because text-size is contained between two ; –  Dec 20 '16 at 17:36
  • @I Love CSS: Well if you mean that the current rules are in place to allow for things like :matches() to be introduced in future specs, then you hit the nail on the head (see the duplicate link), and :matches() is absolutely relevant given that context. – BoltClock Dec 20 '16 at 17:50
  • Thanks for the other links, had a hard time finding finding words so did not found those before posting. I'll guess the best way to look at it, that even tho it is defined behavior which looks counterintuitive, it is the easiest way and robust way to for browsers to deal with it. So the browser cannot guess what the "valid rest" is. Imagine multiple commata "," in :not pseudo class. Or another example if you define multiple gradients by chaining with ",". If one of them is wrong, the entire declaration gets ignored to. – Type-Style Dec 21 '16 at 07:38
  • @BoltClock : HTML tags can't have arbitrary names either ( → even custom HTML5 tags are invalid without the mandatory dash), yet browsers just ignore unknown, invalid HTML tags in a group of CSS selectors (**[see demo](https://jsfiddle.net/dx5n8djo/3/)**). I would expect the same behavior for pseudo-selectors, if only for the sake of consistency. Additionally, making an entire group of selectors invalid forces you to write pretty convoluted CSS code if you want to add support for new pseudo-selectors without dropping support for older browsers. That just makes... no... sense... whatsoever! – John Slegers Dec 21 '16 at 09:31
  • 1
    @John Slegers: HTML's rules on valid element names don't apply to CSS. They're two different languages. So, again, a type selector can have any name. And so the rule isn't discarded because "focuswithin" is otherwise a perfectly valid type selector. There is no reason the CSS grammar has to be restricted to one arbitrary document language. Pseudo-classes and pseudo-elts on the other hand are defined by CSS itself, which is why it defines a specific, finite set of known pseudo keywords. – BoltClock Dec 21 '16 at 10:49
  • @BoltClock : That actually does make sense. I still think it's poorly designed to behave that way ( → because it results in very convoluted code if you care about supporting old browsers), but your explanation definitely makes sense! – John Slegers Dec 22 '16 at 11:28
  • @John Slegers: It's a trade-off, yeah. That's why you see stuff like `::-moz-selection {...} ::selection {...}` everywhere. Oh well! – BoltClock Dec 22 '16 at 11:33

1 Answers1

8

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.

Hubert Grzeskowiak
  • 15,137
  • 5
  • 57
  • 74
  • 5
    I think the question is "Why does the spec say browsers should act this way?" – Quentin Dec 20 '16 at 16:26
  • 1
    "CSS 2 didn't specify what to do when one selector was wrong." It does, [elsewhere in the spec](https://www.w3.org/TR/CSS2/syndata.html#rule-sets). Remember that CSS2 is a monolithic spec. – BoltClock Dec 20 '16 at 16:36