I think one feature we should add to Conditional Rules Level 4 is a feature query function to test for selector support, presumably called selector()
.
I've started a draft of an explainer for this, from which I quote the relevant section:
Having feature queries based on selectors is probably the highest priority addition, both because it seems the most likely to be important in the near future, and because it is the simplest. It has come up recently because CSS authors using the features in the CSS Scrollbars Module Level 1 may want to query for support of those features, and may also want to query for support of the ::-webkit-scrollbar
pseudo-element.
I believe a possible syntax for such a feature was discussed at one point early in the development of @supports
, but I can't find meeting minutes of the discussion. I think the best way to extend the syntax is using a selector()
function, as in:
@supports (scrollbar-width: thin) or selector(::-webkit-scrollbar) {
#chatwindow { overflow: scroll; scrollbar-width: thin }
#chatwindow::-webkit-scrollbar { width: 5px }
}
It is worth noting that this usage requires that the selector()
feature query function not copy the quirks that are present in selector parsing, where all ::-webkit-*
pseudo-elements behave as though they're supported (and allow the selector to parse). Instead, inside of the selector()
feature query function, this quirk should not be present, and a selector()
function containing a ::-webkit-*
pseudo-element should only be true if the pseudo-element is actually supported.
Other than this, the function should work just as the tests for support/validity work in the rules on handling invalid selectors.
I agree that this is useful and high-priority among possible @supports additions, and think that's the right syntax.
Great idea!
What about other selectors and matching them?
@supports selector(<) {
// use imaginary future < selector
} else @supports selector(:visible) {
// use imaginary future :visible selector
} else {
// use some conventional selector
}
p.s.: no endorsement for those imaginary selectors
selector(<)
would likely fail; it doesn't match the selector grammar. But you could write selector(a < b)
and it would match in a hypothetical world where we added that combinator.
selector(:visible)
would definitely work, exactly the same as dbaron's other examples.
else
is also something we should add: http://tabatkins.github.io/specs/css-when-else/ ^_^
so maybe selector-operand(<) {}
? not sure forcing one to add virtual dom elements to check for selector operand support sounds so sane to me...
? You don't have to add any elements. You just have to create a well-formed selector, so we can do a trivial "does this parse as a selector" check. You already know for a fact that a
and b
are valid tagname selectors.
selector(* > *)
would also work if you don't want to choose arbitrary tag names.
I was planning to suggest this.
Also, when it comes to functional selectors, I presume that the brackets are necessary (eg. selector(::slotted(*))
will need to be used)
This will also go hand in hand with https://github.com/w3c/csswg-drafts/issues/3082, which would allow simplifying:
@supports selector(A) or selector(B) {
// do stuff
}
to
@supports selector(A, B) {
// do stuff
}
Where A
and B
are little supported selectors, eg. :matches()
or :has()
.
I think I'd prefer if we just used the <selector>
syntax. Using a <selector-list>
looks like different arguments to the function, and it wouldn't be clear whether the semantics are all
or any
.
Plus the <selector>
syntax can be extended later if needed, but not the other way around.
I meant <complex-selector>
, btw.
Should namespace prefixes in the selector be checked against the prefixes declared in the style sheet it's used in, or should all prefixes be allowed, since we're really just checking for syntactic correctness of selectors that the browser understands? And if we should be checking them against the declared prefixes, should any namespace prefix usage in a CSS.supports("selector(...)")
call evaluate to false?
I think we are just checking syntactic correctness, as *|*
is a valid selector even without a @namespace
declaration, IIRC.
A missing namespace is a parse error everywhere else, I'd rather be consistent on _rejecting_ it, since not doing that introduces a special-case, and other APIs like querySelector
already throw on that, like (for example, document.querySelector("a|b")
throws, doesn't return null).
FWIW the namespace question came during the code review of https://bugzilla.mozilla.org/show_bug.cgi?id=1499386.
The CSS Working Group just discussed Selector feature query function for selectors
.
The full IRC log of that discussion
<mstange> Topic: Selector feature query function for selectors
<Rossen> github: https://github.com/w3c/csswg-drafts/issues/3207
<mstange> dbaron: When we discussed @supports back w hen we originally did it, one of the things we talked about that we maybe want to have support for more than querying for values
<mstange> dbaron: There may be more important use cases
<mstange> dbaron: Next addition would be testing for selectors
<mstange> dbaron: If you have three comma-separated selectors, the entire rule is supposed to get dropped if any of tehm is unrecognized.
<mstange> dbaron: This is painful because you don't get good negation operations.
<mstange> ... It has also come up recently when looking at scrollbar styling.
<mstange> ... @supports is useless for existing scrollbar styling use cases
<mstange> ... because some of them use selectors
<mstange> ... We all agree on what the syntax of testing for selectors should be, which is, it should be a function called selector.
<mstange> ... We want to allow combinators.
<mstange> ... There are currently some quirks related to ::-webkit pseudo elements
<mstange> ... There is a quirk that makes all ::-webkit pseudo elements not invalidate the selector
<mstange> ... We do not want to carry over this quirk to @supports selector
<mstange> heycam: There is an open question about namespace testing
<myles_> https://bugs.webkit.org/show_bug.cgi?id=189089
<mstange> dbaron: This turns out to be a bug in existing @supports because we didn't define it for content: attr(?)
<mstange> ... We should figure out how it interacts with @namespace prefix declarations
<mstange> TabAtkins: I'm fine with not having them
<mstange> ... I definitely do not want to look at namespace, should either fail or pass always
<mstange> fantasai: I agree
<mstange> dbaron: I would lean towards saying the always succeed and act as they always match the namespace
<mstange> emilio: I would like to argue for the opposite, we sohuld actually look at the namespaces in the stylesheet
<mstange> emilio: If you are testing for a selector that you actually use inside your @supports rule, that's what you want.
<mstange> ... It also doesn't require any special cases in the implementation.
<mstange> Bert: Isn't that the point, to ask whether you support "this type of selector", not "this particular selector"?
<dbaron> s/Bert/plinss/
<mstange> emilio: I would argue that if it's an unknown namespace, you should not go into the @supports rule
<mstange> emilio: Invalid namespaces are invalid, they drop the whole rule
<mstange> emilio: just doing syntactic checking is inconsistent with other DOM APIs that throw on invalid selectors
<mstange> emilio: Like .matches
<mstange> TabAtkins: Can we make them always invalid?
<mstange> emilio: I'd prefer that over making them always valid
<mstange> dbaron: There's a risk with newly-supported selectors in the future
<mstange> emilio: Please don't introduce a special case
<mstange> TabAtkins: The matches function always ignores namespaces, because it always throws when there's a namespace
<mstange> emilio: because there's no stylesheet
<mstange> fantasai: There's a rule in the matches spec that talks about namespaces, but it doesn't make it invalid
<mstange> dbaron: The other thing about the selector functions is that at some point the drafts of those functions had a namespace argument that got dropped.
<mstange> heycam: With CSS prefixes on the DOM node, no namespace prefixes are going to succeed except * or |
<mstange> TabAtkins: That same behavior seems fine to have for @supports
<mstange> fantasai: That doesn't make sense
<mstange> fantasai: I want to check whether I support a selector. Any selector that I'm using in my stylesheet, I should be able to put it into @supports
<mstange> emilio: I agree.
<mstange> fantasai: Which is not what TabAtkins is saying.
<mstange> fantasai: .supports would still return "yes I support namespaces"
<mstange> ... it's not about "Does querySelector" support this
<mstange> fantasai: We're checking things at the syntactic level
<mstange> fantasai: I'd be ok with checking the namespace whether it resolves
<mstange> emilio: I would prefer to look at the namespace map, if it's around
<mstange> emilio: Then we don't conditionally need to make all namespaces valid in some cases.
<mstange> emilio: The rules in @supports should be the same rules as for regular parsing.
<mstange> TabAtkins: What do you think about changing the regular parsing rule of "bad namespaces" kill the rule?
<mstange> futhark: I tend to agree for regular namespaces. If we're not checking namespaces, I prefer that we actually allow namespaces.
<mstange> emilio: So either check the namespace map as normal, or always succeed.
<mstange> dbaron: We need another resolution first, which is to create level 4 of CSS conditional rules
<mstange> ... unless we want to put this in level 3
<mstange> Resolved: Create CSS conditional rules level 4
<mstange> Resolved: Accept selector feature functions for selector support in @supports, accepting a single complex selector as an argument.
<mstange> dbaron: Do we want a resolution or two about the namespace thing?
<heycam> the namespace prefix issue is https://github.com/w3c/csswg-drafts/issues/3220
<mstange> fantasai: For the namespace we've resolved that they're not always invalid.
<mstange> Resolved: Namespaces are either always valid or valid when they're declared.
I know we are talking about syntax for a feature query, and a lot has already been brought up, but wanted to make sure it was addressed that previously the concept of a "selector" query was mentioned to match a selector against the current state of the document.
In https://github.com/w3c/csswg-drafts/issues/112#issuecomment-221672439 @tabatkins said...
@fantasai So if we pretend there's a selector() function that is true if something on the page matches that selector, I think you'd write:
@when selector(body.toc-inline) or (media(width < 28em) and not selector(body.toc-sidebar)) {
/* inline ToC styling /
} @else {
/ sidebar ToC styling */
}
Figured it worth mentioning, even if some other syntax like query()
could be better.
_Edit - I know this is unrelated apart from possible naming/syntax similarities that should be kept in mind._
Yeah, that's a completely unrelated proposal.
From the IRC log above:
RESOLVED: Create CSS conditional rules level 4
RESOLVED: Accept selector feature functions for selector support in @supports, accepting a single complex selector as an argument.
RESOLVED: Namespaces are either always valid or valid when they're declared.
So, what鈥檚 the progress on writing a spec for this?
I鈥檓 asking because Mozilla wants to ship this in bug 1513643.
We're not shipping it without writing the spec.
Chrome has shipped https://bugs.chromium.org/p/chromium/issues/detail?id=979041#c13
Most helpful comment
selector(<)
would likely fail; it doesn't match the selector grammar. But you could writeselector(a < b)
and it would match in a hypothetical world where we added that combinator.selector(:visible)
would definitely work, exactly the same as dbaron's other examples.else
is also something we should add: http://tabatkins.github.io/specs/css-when-else/ ^_^