New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[selectors] Let :is() have better error-recovery behavior than normal Selectors #3264

tabatkins opened this Issue Oct 29, 2018 · 10 comments


None yet
7 participants

tabatkins commented Oct 29, 2018

This isn't captured in the current spec, but I remember earlier speculation that we could use :matches() as a way to get around the bad Selectors behavior of "a syntax error in one complex selector invalidates the whole sequence" that we're stuck with. Do we still think this is a worthwhile idea to pursue?

Spec-wise, what this would mean is defining the official syntax as :matches( <any-value> ), then split the result on top-level comma tokens, then attempt to parse each item as a <complex-selector>, and just ignore any invalid ones. (If all of them are invalid, the selector matches nothing.)

Then, if you're concerned about using a newer feature, you can just write your selectors like:

:matches( .foo || .bar, ) {
  /* styles for the bar cell */

An unfortunately, but relatively minor, tax for getting better error-recovery behavior. (If we do end up renaming it to :is(), it's even more minor.)


This comment has been minimized.

CyberAP commented Oct 29, 2018

Shouldn't this belong to @supports rule?
Just to imagine how bloated stylesheet would get if you have to use new selectors extensively. While with @supports you can only test it once and that's it.
Yes it doesn't cover selector check right now, but with Custom Selectors from CSS Extensions this should be possible.


This comment has been minimized.


SelenIT commented Oct 29, 2018

@CyberAP, the point is to avoid having to write the same rules twice (for new and all browsers).

For example, consider a menu that is by default transformed into a hamburger icon (or something), but should "uncollapse" if either hovered or has a link inside it focused via keyboard. For modern browsers, I can write

.menu:hover, .menu:focus-within { transform: none; }

...but in browsers that don't support :focus-within this would not apply at all, and I would have to write this rule twice, for each selector separately, in order to make at least the :hover part work there.

However, with the new proposal, the following hypothetical example

:is(.menu:hover, .menu:focus-within, :current(.menu)) { transform: none; }

would be able to work in browsers that already support :is() and these two pseudo-classes, but don't support :current() yet.

How can this be solved with @supports (even if extended to test for selectors)? For me, this looks like the opposite of what @supports does (combining the code for old and new browsers into one rule, rather than separating it into different rules). Would be happy to be proven wrong!


This comment has been minimized.

CyberAP commented Oct 31, 2018

@SelenIT, thanks for a great explanation! That does make sense and actually is a really great feature I would like to have.


This comment has been minimized.

ExE-Boss commented Nov 2, 2018

You mean like #3082, except without the vendor prefix exemption?


This comment has been minimized.


tabatkins commented Nov 2, 2018

Yes, and safely; I'm pretty sure we can't do #3082.


This comment has been minimized.


css-meeting-bot commented Nov 21, 2018

The CSS Working Group just discussed Let :matches() have better error-recovery behavior than normal Selectors, and agreed to the following:

  • RESOLVED: Use media query style invalidation inside pseudo classes that accept selector lists
The full IRC log of that discussion <dael> Topic: Let :matches() have better error-recovery behavior than normal Selectors
<dael> github:
<dael> Rossen: Is TabAtkins on?
<dael> fantasai: I can take it
<dael> fantasai: When we have a list of selectors :foo, :bar
<dael> fantasai: Browser doesn't rec :foo so the entire style rule is thrown out
<dael> fantasai: That's selectors invalidation.
<dael> fantasai: Other style of invalidation is media queries-like where you throw out a section. So if you have foo, screen we recognize screen
<dael> fantasai: Can't do MQ like because it would break the web for selectors. TabAtkins pointed out we have ability to do it within the new selectors in L4
<dael> fantasai: Issue proposes we adopt MQ-like invalidation inside the pseudoclasses that take selectors.
<dael> fantasai: :foo || :bar, [known selector] we'd only do the part we recognize.
<dael> fantasai: Makes a lot os sense to me together with @supports rule we added. Gives authors much better tools. If they want more granular they can use something else
<dael> Rossen: Sounds reasonable.
<dael> Rossen: Opinions?
<dael> myles: Thoughts from people that teach this? Seems like could be confusing
<dael> Rossen: leaverou or rachelandrew ?
<dbaron> Were you suggesting doing different things for :matches() vs. :is() ?
<tantek> agreed with myles, it could be confusing. would definitely want webdev teacher feedback on this.
<dael> fantasai: dbaron this was from before we renamed. Title should be is. Applies to is, not, has, nth-child, and maybe current
<dael> dbaron: One worry is some have been around for a while and might have compat issues
<dael> fantasai: :not with commas isn't widely supported.
<dael> fantasai: Not with a single argument that's invalid makes the whole thing invalid
<dael> florian: I think not with a comma is supported in Safari and Viviostyle
<dael> fantasai: Not is trickier because it's a negation
<dael> leaverou: Trying to decide error recovery or syntax?
<dael> fantasai: Error recovery
<dael> leaverou: Sounds amazing thing to do. It might be a little confusing, but it's worth it. In talks I only use webkit version and have to mention verbally it's just webkit. As an author I would love it
<dael> emilio: Doesn't solve unknown pseudo elements issue, right?
<dael> fantasai: No, sep.
<dael> emilio: I think that's biggest issue authors want to solve
<dael> fantasai: There's a rule for the webkit
<dael> emilio: Want to style a video control for webkit and edge it's not stanard. That's the biggest source of duplication
<dael> fantasai: This would solve, put it in all one :is
<dael> emilio: Syntax allow psuedo elements inside?
<bradk> I’m still concerned about :not. Can we find out how much authors have :-webkit and commas inside not?
<dael> fantasai: This is work for pseudo classes. Elements is next on agenda
<florian> I support this
<dael> Rossen: bradk point about not and his concern, can we address that now?
<dael> Rossen: Concern is the :not and defining how much authors have commas inside a not?
<dael> florian: It's safari only
<dael> bradk: Safari on iphone is used a lot. :not has been without commas for a while, but it's used in mobile web a lot. That's my suggestion, I'd like actual data
<dael> florian: This is hard data to get. Need to find usage that would break the page if it started working in a different way. That's a judgement call
<dael> Rossen: Another way to ask is if any Apple folks have an issue with this. If they feel comfortable with compat risk we can resolve
<dael> bradk: That solution would be okay
<dael> smfr: I don't think we have enough [missed]
<dael> smfr: I don't thinkw e have enough information to know. When we impl :not we got compat issues b/c people using it in wrong ways
<dael> smfr: No feeling for how common comma use is to know if it's risky
<dael> Rossen: Would you be okay with current proposal in the absense of this information?
<dael> smfr: I think so
<dael> Rossen: Anything else before we try and resolve?
<bradk> No strong objection
<dael> fantasai: Use media query style invalidation inside psuedo classes that accept selector lists
<dael> Rossen: Objections to ^?
<dael> emilio: Would like behavior for :not clarified
<dael> fantasai: Makes sense
<dael> RESOLVED: Use media query style invalidation inside pseudo classes that accept selector lists
<dael> Rossen: fantasai and TabAtkins will have clarification in spec

This comment has been minimized.


fantasai commented Nov 21, 2018

emilio pointed out that we need to be careful about how we handle :not() here. It's not obvious it would work as intended if we just ignore unknown arguments, and also a single argument to :not() likely has Web-compat implications since it's already implemented.

A related question is :nth-child(); simply ignoring one of its arguments could throw off the count. There likely wouldn't be a Web-compat problem with it, though.

@fantasai fantasai changed the title from [selectors] Let :matches() have better error-recovery behavior than normal Selectors to [selectors] Let :is() have better error-recovery behavior than normal Selectors Nov 21, 2018


This comment has been minimized.

ExE-Boss commented Nov 21, 2018

The thing about :not() is that only the single‑argument form is supported in major browsers, so we could probably apply it to the multi‑argument form and be fine.

Also, at least for unknown pseudo‑classes, we could have those match nothing, so :not(:unsupported, :unsupported-2) would match everything because :not(:is(:unsupported, :unsupported-2)) would match everything, as :is(:unsupported, :unsupported-2) would match nothing.


This comment has been minimized.


ewilligers commented Nov 23, 2018

I agree that we could minimize the Web-compat risk by saying that error recovery only applies if two or more selectors are supplied.

:nth-last-child(:nonsense) is invalid
:nth-child(:nonsense, :enabled) is :nth-child(:enabled)
:not(:nonsense, :gibberish) is *
:is(:nonsense, :gibberish) is :not(*).

This would have the following benefits:

  • :not(.) and :nth-child(.) and :nth-last-child(.) with a single selector have the same semantics as in Selectors 3.
  • We have error recovery for :is(...) and :where(...) and :has(...)
  • :not(...) and :is(:not(...)) and :not(:is(...)) are always equivalent, same for :nth-child and :nth-last-child

As a minor variation, preserving the same benefits, we could say that error recovery only applies if at least one of the selectors is valid. Then

:not(:nonsense, :gibberish) is invalid.

This might be easier to teach, and avoid developers' confusion when they see an introduced :not(*) in a Developer Tool that hasn't preserved raw text.


This comment has been minimized.

ExE-Boss commented Nov 23, 2018

As a minor variation, preserving the same benefits, we could say that error recovery only applies if at least one of the selectors is valid.

Then :not(:nonsense, :gibberish) is invalid.

That should probably only apply to :not(…), as :commonly-supported, :is(:rarely-supported) can be used to avoid invalidating the entire selector list if the :rarely-supported pseudo‑class isn’t supported by the current browser but :is(…) and :commonly-supported are supported by the current browser.

Also, it might be a good idea to still parse :not(:nonsense, :gibberish) as valid, but matching nothing.

aarongable pushed a commit to chromium/chromium that referenced this issue Nov 29, 2018

CSS: Use count :not with selector lists
CSS Selectors 4 allows :not to accept selector lists.

There is a proposal for invalid complex selectors in the list to
be ignored (instead of causing the whole selector to fail parsing.

This would affect :is :where :nth-child :nth-last-child, :has and :not,
with the main compatibility risk being :not.


We add use counters to estimate the Web compatibilty risk.


Change-Id: I708d48d626a6e61cc8c1076d40d2c33bb19496e3
Reviewed-by: Rune Lillesveen <>
Commit-Queue: Eric Willigers <>
Cr-Commit-Position: refs/heads/master@{#612177}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment