In Issue #1170 we decided to add a functional pseudo-class that is exactly like :matches()
but has zero specificity. However, we didn't decide on a name.
Suggestions in that thread included :is()
, :when()
, :filter()
, and :nospecificity()
. It was noted that having :filter()
as a selector and filter
s a property might be confusing, and that :nospecificity()
is a pain to type. Additional suggestions, comments, and clarifications welcome.
I would vote for :is()
. It's short, and it explains what it does. IIRC most people were in favor of :is()
both in the thread and at the F2F. If you want an explicit resolution, we could add it to the agenda.
This is the twitter thread where I asked authors for ideas: https://twitter.com/LeaVerou/status/928426600558862337
As you will see, the results are not very useful.
Regarding the other names:
:when
sounds time-related:nospecificity
is ridiculously long and prevents any possibility of expansion in the future to allow setting specificity, as @tabatkins suggested.:filter
is confusing because it sounds related to the filter
property and the filter()
function.
:nospecificity
is ridiculously long and prevents any possibility of expansion in the future to allow setting specificity, as @tabatkins suggested.
At least the latter point could be avoided, of course, by using :specificity()
instead. Nonetheless it's still very long and hard to write.
So, I also vote for :is()
, even when it rather indicates a check and not something to _set_ the specificity.
Sebastian
I'm for :is()
, as it :is()
easy to memorize as kind of acronym for "Ignore Specificity" :)
Since #1170 was already resolved it may be too late for this, but shouldn't #1027 be resolved before adding a new functional pseudo-class?
It seems probable to me that the specificity of :matches
needs to be fixed to avoid performance problems in some cases, and then :is
could become redundant.
Iâm not sure that :matches()
can, and needs to, be âfixedâ. For me, the summary of #1027 is that :matches()
doesnât have any special performance problems per se (except it allows to write seemingly short selectors equivalent to terribly long selector lists, but this problem is not new, it often occurs with CSS preprocessors as well). Also, :matches()
has been supported in Safari since 2015, and there is intent to implement it in Chrome, so changing it can break the interoperability. And, AFAIK, it wasnât meant to affect specificity in any way, itâs sole purpose was to be syntactic sugar for shortening the lists of selectors with common parts for readability and reducing style bloating. The :is()
selector, on the other hand, was introduced specifically to explicitly control the specificity, so I doubt that it could become redundant.
Yes, just syntax sugar, but the problem is that if you just desugar it naively then you get an exponentially-long selector. Preprocessors don't matter, what matters is the CSS they produce, and it's acceptable for a CSS engine to take more time if the CSS is absurdly huge. But if the CSS is not huge, then it should be fast (e.g. that's why :has
is not allowed in the dynamic profile).
If Safari implemented :matches
, maybe there is some efficient algorithm. But I suspect they might not be calculating the specificity of :matches
on the element that ensures a maximum specificity, which probably is what the spec should properly define. Sadly I have no Mac to test.
My concern with :is()
is that it will be logically seen as the inverse of :not()
, even though the inverse of :not()
is :matches()
: the specificity behavior of :not()
and :matches()
are matched, and :not(:not(selector))
behaves as :matches(selector)
, not as :is(selector)
. But linguistically âisâ and ânotâ seem to form a pair.
What about swapping :is
and :matches
, then? So :is
would be analogous to :not
and :matches
would have 0 specificity.
Well, maybe then we can avoid the confusion if we could use the pattern proposed in #1170 by @tabatkins and add an extra optional argument to the existing :matches()
_instead of_ duplicating its functionality in a new pseudo-class at all?
So while :matches(...)
would behave as it currently does, for example, :matches(... as 0,0,0)
would have the behavior of the proposed :is()
(zero-specificity matching), and :matches(... as 0,1,0)
would match any of its arguments with the specificity of the single class. It would be backwards compatible with the existing :matches()
implementations and wouldn't introduce any ambiguity in what is the inverse of :not()
. Moreover, the similar extra argument could be added to :not()
as well, making the behavior of :not()
and :matches()
symmetric.
Or is it too late to make such changes in Level 4?
Yup, we could rename :matches()
to :is()
and introduce an extra argument, which could only be 0 at first, and later expand to the full specificity triplet.
I.e. div:is(#foo, as 0)
.
Wouldnât renaming :matches()
require making it an alias for :is()
? Or will it make the existing WebKitâs shipped implementation (and probably the Blinkâs implementation being currently developed) non-conforming?
We're not renaming :matches()
; it's already shipped in Safari and I think Firefox and Chrome are soon to ship?
I'm still okay with just adding the functionality to :matches()
, with the default being the current "specificity of the most specific branch that matched". If we do make a separate function, I'm still happy with :is()
; the possibility for confusion is there, but oh well.
So since when has short-lived vendor implementation ruled what happens to a standard?
I don't get it what's wrong, this is not yet another piece of software that you (or someone else at big-vendor-x) can throw away in some years and replace it with something else entirely and somehow I got the feeling that that's the recent predominant mind set. /rant :-(
Without much details to rephrase what @fantasai says:
:not()
and :matches()
are the inverse of each other they should have inversed names for easy understanding and usage.:is()
and :not()
have inversed semantic meaning, they should behave like that and not unexpectedly do something else.Logical options that make sure developers in future are not the hell confused about it (and TWBS-div-soup-hell shows most, are):
matches()
to is()
- use matches()
for the new 0-specificity feature discussed here.is()
and matches()
and find a new name for the feature proposed here instead of matches().So why don't we collect alternate names for the current matches()
-proposal and if we can find something really reasonable we can alias is()
and matches()
and deprecate matches()
? What's so wrong about that?
If my last comment is true, that would leave us with:
:nospecificity()
- Agreed that it is hard to type, long, wants me to write :no-specificity()
instead, wants me to add typos to "specifity"
by accident and leaves no option to add specificity features later on. Pretty much worse than :is()
, IMHO.:filter()
- I rather much would have the same word in different contexts doing different things (as expected), than logical pairs of words doing something else (:is()
vs :not()
).:when()
- I don't think the interpretation as only "time" related is a problem @LeaVerou? LESS, Elixir and PostgreSQL use it for logical conditions just fine, so why is ":when sounds time-related" a problem?So these are all sane options without creating unexpected developer pain:
matches()
for the new implementation and rename current matches()
implementation in the wild to is()
- Issue: Vendor Safari has to adapt.when()
for the new implementation and alias current matches()
to is()
and deprecate matches()
- Issue: None?filter()
for the new implementation and alias current matches()
to is()
and deprecate matches()
- Small Issue: re-use of the same word in different context means it does different things.Edit, here are some more from @LeaVerou's Twitter post.
:extend()
:decorate()
:augment()
:if()
:catch()
, and I'd like to add::apply()
:case()
Aliasing :matches()
doesn't do much of value; the name as it stands is fine, so it's not worth adding yet another name for the same functionality. That just makes it harder to teach and understand.
Renaming :matches()
is rude to the implementors at this point, and to the authors who've already learned it. We've had the function for a long time, implementors have begun implementing with it. If the name was truly bad or misleading we could probably rename it, but it's not - at worst, it's slightly annoying that :is()
appears to be a slightly better antonym to :not()
than :matches()
is, so people new to the feature might get confused, but it's quick to learn which is which. At this point in the feature's maturity, I don't think this justifies making a name change.
@inoas, AFAIK, :matches()
is not just "short-lived vendor implementation". It has been in the standard draft for years (although the definition has changed a little), and its shipped implementation, without any flag/prefix, has existsed since mid-2015 (deprecating the old vendor-specific :-webkit-any()
implementation), and there is intent to implement it in Blink (1, 2). So there should be some really solid reasons to rename/alias it (IMO).
Hovewer, I agree with Tab that the potential confusion in meaning between :matches()
and :is()
is not a very important issue. So I'm also fine with the both options â either introducing :is()
as a functional analog for :matches()
that ignores specificity (as currently specified), or "overloading" :matches()
with an optional extra argument, without adding new pseudo classes at all.
In the past we would keep bad things only to avoid breaking web compat. Now we're keeping bad things to not be "rude" to implementors? What fresh hell is this?! đ
:matches()
has shipped in one browser and is not used by anyone. Renaming things is typically easy for implementors, and since nobody uses it (outside of postCSS) it doesn't break web compat.
What troubles me more is that I expect :is()
to be used many more times in a selector and the lengthier :matches()
would end up messing with readability. :matches()
is only used for > 1 alternatives, whereas :is()
is useful for singular things too. I think a name for :is()
that's longer than 2-3 characters would be a pain.
@leaverou I will note that most of your examples are chains of :not()
which in Level 4 could be expressed within a single :not()
, which won't explode the specificity in the same way. E.g. :not(.A):not(.B):not(.C)
(specificity=0,3,0) can be written as :not(.A, .B, .C)
(specificity=0,1,0).
In the past we would keep bad things only to avoid breaking web compat. Now we're keeping bad things to not be "rude" to implementors? What fresh hell is this?! đ
It's not a "bad" thing. It's a perfectly serviceable and appropriate name that people were happy with for multiple years; two people in this thread suddenly expressing a preference for a slightly different name does not make the original name bad.
Changing things that have shipped, are about to be shipped, that have tutorials written about them, etc., is expensive. It's one more thing a browser implementor has to do (even if it's "trivial", it's still a chunk of time out of someone's day to update the parser, the tests, maybe the DevTools support, and that chunk could have been spent doing something more valuable), and it means a lot of tutorial content in the wild is invalid and needs to be updated, or is just confusing in the future. In other words, renaming is not free, and the longer the name lives out in the wild, the more expensive it becomes. This doesn't mean we can't do it, but it does mean we need a decent reason to do so, and "some people suddenly decided they like this alternate name slightly better" is not a very good reason, or at least not a good enough one to override the costs in this case, in my opinion.
Well @tabatkins it is not like the only option is renaming aliasing and adding is()
, actually when using when()
here for this proposal there is the option (not) to later on alias is()
with matching()
and/or make it a separate stand-alone issue as it is not strictly related then, anymore.
Using when()
would also circumvent the issue of semantic (but proposed non-functional) pairing of is()
vs not()
.
Would that be viable?
@LeaVerou maybe Brent Spiner knows.
@LeaVerou I will note that most of your examples are chains of :not() which in Level 4 could be expressed within a single :not(), which won't explode the specificity in the same way. E.g. :not(.A):not(.B):not(.C) (specificity=0,3,0) can be written as :not(.A, .B, .C) (specificity=0,1,0).
Just because it's easier to demonstrate the problem with :not()
because typically removing something very specific from a large set still leaves you with a large set, so its specificity is almost always not what an author wants. Note that div:not(#foo, #bar, #baz)
has the same problem, just less specificity. It's still pretty hard to override even just one id selector.
However, the problem :is()
is trying to solve extends way beyond :not()
. I could go through my stylesheets and compile a list of use cases that have specificity problems and don't include :not()
. Thankfully, we have a resolution on this, so my time can be spent more productively.
Can we please focus on the name?
I think @SelenIT made an excellent point about :is()
being an acronym for Ignore Specificity.
Thankfully, we have a resolution on this, so my time can be spent more productively. Can we please focus on the name?
I'm not disputing that we should have this feature, just the frequency with which it would be needed that is driving you to require its name to be two characters.
I think @SelenIT made an excellent point about :is() being an acronym for Ignore Specificity.
And as you so often like to point out, nobody reads documentation, so my point about the misleading pairing stands, however clever the backronym might be.
Should the :is() have specificity like :not()?
What specificity has :has()?
What specificity has :has()?
:has is only available in the snapshot profile, thus I suspect it doesn't need to have defined specificity. The query() method does not consider specificity.
Should the :is() have specificity like :not()?
@Nadya678 :matches()
behaves like :not()
: it takes the specificity of its argument. The proposed :is()
, which otherwise behaves exactly like :matches()
, has a specificity of zero.
What specificity has :has()?
Good question. It looks like we forgot to define it when we switched from having a subject indicator to using :has()
syntax. I've updated the Specificity section now--it has the specificity of its argument, just like :matches()
.
Another option, fwiw, would be to use bare parens for eliminating specificity. There are two possible interpretations of this idea:
A. Treat it like a pseudo-class syntax, except without the preceding :foo
.
B. The selector is interpreted exactly as if the parentheses weren't there, except that any selectors inside the parentheses aren't counted for specificity.
Example: foo(.a > .b) .c
-- A would match this as foo:matches(.a > .b) .c
whereas B would match it as foo.a > .b .c
For case B, if it's considered weird, we could say that the parens can't cross hierachical boundaries, i.e. that example above would be invalid, but you could write foo(.a) > (.b .c)
to mean the same thing.
That syntax doesn't work; it confuses the parser and produces paren-blocks in some cases, but function-blocks in others, and when it looks like a function, it isn't one. foo(.a > .b)
appears to be a function named foo()
to the parser.
Another option, fwiw, would be to use bare parens for eliminating specificity. There are two possible interpretations of this idea:
I was wondering about something like this, perhaps an empty pseudo-class (foo:(.bar)
). But is this important enough to be privileged like this? It might be, but since we can only allocate the empty pseudo-class once we need to think about this.
My opinion is: strongly no. We shouldn't allocate the "empty pseudo-class" for anything at all, imo - it's an impossible syntax to google for or even to talk about casually.
Is this not a concern to anyone but @fantasai and me?
My concern with :is() is that it will be logically seen as the inverse of :not(), even though the inverse of :not() is :matches(): the specificity behavior of :not() and :matches() are matched, and :not(:not(selector)) behaves as :matches(selector), not as :is(selector). But linguistically âisâ and ânotâ seem to form a pair.
So @LeaVerou what about :when()
then or :case()
?
Maybe it's worth considering :as()
instead of :is()
? Still only 2 letters, but it clearly doesn't pair with :not()
. It implies that the selector is basically still the main selector (part before :
), but in a special state or situation where it acts (also) _as_ another selector, where it "mimics" that other selector, where it _only plays its role_ â which quite intuitively describes what this selector does (at least, for me).
I like :as()
!
:case()
is unclear and :when()
sounds time-related (as I said in the second comment).
At this point, we have been bikeshedding names for a month (9 months if you start counting when the initial proposal was posted). We have seen many proposals, and I don't think a clearly better one will magically emerge if we discuss this for another month. The feature has already started being shared amongst authors, presented in a Google podcast, and people are generally excited, so as important as naming is, it would be good not to hold it up further with even more bikeshedding.
I will go ahead and add this to the agenda for next week, so we can do a straw poll and finally decide. Hope thatâs ok with you @fantasai!
Here is a summary of all proposals (feel free to edit my comment to add pros & cons, or any proposals I missed):
| Name | Pros | Cons |
|-------|------|------|
| :is()
| short, meaningful, backronym for "Ignore Specificity". | logical opposite of :not()
|
| Rename :matches()
to :is()
, use argument for specificity | Avoids 2 pseudos for same functionality, logical opposite of :not()
, short | :matches()
shipped in Safari and in draft for years |
| :matches()
(and rename :matches()
to :is()
) | :is()
is the logical opposite of :not()
| Long, :matches()
shipped in Safari
| :matches(...,... as 0,0,0)
| Avoids 2 pseudos for same functionality | Looks like a single list with entries ...
, ... as 0
, 0
, 0
| :when()
| meaningful | looks time-based
| :if()
| Short | People might also expect :else
| :also()
| implies argument has subsidiary role | ?
| :as()
|short, not opposite of :not()
| Sounds similar to :has()
| :filter()
| ? | Confusing, looks related to the CSS filters
| :nospecificity()
|Explains exactly what it does | Way too long, can't be extended to specify specificity
| :extend()
| ? | Sounds related to @extend
|
| :decorate()
| ? | Too long, convoluted
| :augment()
| ? | Too long, convoluted, especially for non-native speakers
| :catch()
| ? | Confusing, Sounds error-related
| :apply()
| ? | ?
| :case()
| ? | unclear
| :switch()
| ? | ?
| :cond()
| ? | ?
| :isset()
| ? | ?
| :defaults()
| ? | may be confused with :default
| :something()
| ? | ?
| :selects()
| ? | ?
| :where()
| used to winnow sets in SQL | ?
| :fallback()
| means an alternative when nothing more specific is available | ?
| :general()
| antonym of specific | ?
| :sub()
| lower level or position, abbreviation of substitute | ?
| :weak()
| means being susceptible to substitute | ?
I'm not sure I follow the logic for :as()
; to me it implies we're translating the selector to its argument.
But maybe add :also()
to the list? (It's almost as short, indicates conjoining the restrictions in its argument to what's it's attached to; but also implies a structurally-branching or subsidiary role for its argument, so making it âless importantâ by dropping its specificity fits into that connotation.)
:has and :as sound very similar.
We're not renaming :matches(); it's already shipped in Safari and I think Firefox and Chrome are soon to ship?
Could we have metrics about current :matches() usage in the wild? @inoas 's argument « So since when has short-lived vendor implementation ruled what happens to a standard? » does ring a bell here. If, as @LeaVerou says, :matches() is unused or almost unused (plausible since 95% of the market does not have it yet), we have NOW a window of opportunity to change it if we want.
That said, I am not sure I like the "as" extra argument proposal. In terms of parsing, we would need a separator between the end of the last compound selector and the specificity marker to avoid confusion with a "as" type element selector... The easiest to use is the comma but then we have the same problem again, the selector list parser will resume with "as" and only a look-ahead will help; but still, what if I'm applying "as f0" selector to my own XML dialect where "as" and "f0" are real elements but I make a typo and drop the leading "f"? Is that a buggy selector list or a buggy specificity marker? All in all, the ", as ..." solution seems to me too hacky. I have then a preference for two pseudos, one with a specificity and a second one without.
Extra note, I don't like the fact that two features having same exact definition if you except the specificity have too different names. That's why I don't really like :is(). I would prefer :matches() and :matches-_blah_() with a good choice for _blah_...
AFAIK, :matches() is not just "short-lived vendor implementation". It has been in the standard draft for years (although the definition has changed a little), and its shipped implementation, without any flag/prefix, has existsed since mid-2015 (deprecating the old vendor-specific :-webkit-any() implementation), and there is intent to implement it in Blink (1, 2). So there should be some really solid reasons to rename/alias it (IMO).
A "draft" is NOT a standard. Second, Selectors 4 have never been in CR, and :matches() has never been in a REC-track version of Selectors 3. So this is yet another occurrence of vendors potentially disturbing standardization with a "shipped, can't change" argument and, holy cow it's 2018, could vendors please stop doing that? Oh but wait, it's not even shipped yet, an "intent to ship" is not "shipped". It smells far too much like 1997 Microsoft and, fortunately, Microsoft stopped doing that two decades ago.
@therealglazou thanks for your very well reasoned answer! You make some excellent points.
I agree that "as" syntax for extra argument wasn't a good idea. But maybe with better way to do it (e.g. with a simple comma separator, as in @tabatkins's initial proposal) the idea to reuse the same pseudo-class for both default-specificity and zero-specificity/custom-specificity matching would be not so bad? At least, it completely solves the "different names for the exactly the same thing except..." problem.
Unfortunatly, Apple has shipped the :matches()
(and several other selectors from Level 4) implementation with no prefixes or flags back in 2015, in Safari 9.0. I agree that doing it while the spec was far from CR was not the right move from Apple. However, as @tabatkins mentioned, :matches()
is now not only in the spec draft and Apple's implementation, but also in many docs and guides for web devs, in the compatibility tables like caniuse.com, in the lists of modern CSS features like cssdb (where it is marked as "Allowable"), and there are polyfills and PostCSS plugins for it. Changing it without _really good_ reasoning would punish not only Apple, but also authors and users of all these resources. There are also many CSS features (e.g. transforms, transitions and animations) that are implemented with "rough interoperability" and are widely used despite having never been in CR. I'm afraid that making CR status too important could possibly lead to "no implementation before CR/no CR before two implementations" deadlocks.
A "draft" is NOT a standard. Second, Selectors 4 have never been in CR, and :matches() has never been in a REC-track version of Selectors 3. So this is yet another occurrence of vendors potentially disturbing standardization with a "shipped, can't change" argument and, holy cow it's 2018, could vendors please stop doing that? Oh but wait, it's not even shipped yet, an "intent to ship" is not "shipped". It smells far too much like 1997 Microsoft and, fortunately, Microsoft stopped doing that two decades ago.
Very well said!
Btw, may I remind you all that gradients were shipped everywhere and we changed their syntax for much less serious reasons than those described here.
@therealglazou While I don't disagree with your argument in general, I do want to point out that Selectors 4 is dramatically behind process-wise, largely my fault since I have neglected it the last few years, and the features that Apple shipped were largely considered to be stable, so I don't fault them for shipping under the circumstances. I think @SelenIT's arguments are also important to consider. Nonetheless it would be good to collect some data. :is()
as the opposite of :not()
would be pretty nice to have, if it's possible to pull off--and it might be if the specificity of existing stylesheetsâ :matches()
arguments are shown to not matter in practice.
@LeaVerou Thanks for maintaining the table. :)
In addition to what @fantasai said...
Btw, may I remind you all that gradients were shipped everywhere and we changed their syntax for much less serious reasons than those described here.
The major churn we introduced with gradients was a terrible mistake and I wouldn't repeat it if I could go back in time. It's absolutely not appropriate to point to as a precedent.
I spent some time reading through the comments and still like input:when([type=number])
better than any of the alternatives.
Also, even though Edge does not support the :matches
pseudo nor plans to support it at the moment, I would like to agree that :matches
is a reasonable name, and does not need to be changed. I'm highly sympathetic with implementors having a feature shipped for years then ultimately having no advantage of it whatsoever because everything gets renamed in the end. The work required to rename a feature is much more important than it seems. You have to update the tests, the comments, the function named after it; seriously I wouldn't want to impose this on Safari if there isn't a clear and obvious reason.
@FremyCompany, how significant is the difference between input:if([type=number])
and the :when()
version? For me, they seem nearly synonymous in this context, but :if()
is shorter and doesn't look time-related...
Could add :cond()
to the table?
For :apply()
negative would be that it is hard to imagine to "apply a selector" and apply leads to thinking of applying css property lists instead... that can be confusing for new users.
@LeaVerou what's the fuss with when
and being time-related. Is that so bad?
Again I will cite how guards work in some languages, and IMHO the thing this new selector should do is pretty much close go guards: The function signature (the selector + specificity) does not change, but we add some additional conditions under which it varies/should be executed:
when
as a guard in LESS http://lesscss.org/features/#mixin-guards-featurewhen
as a guard in Elixir https://hexdocs.pm/elixir/master/guards.html#why-guardsThere is also when as a conditional clause in SQL (which also leads to case):
https://www.postgresql.org/docs/9.4/static/functions-conditional.html
https://docs.microsoft.com/en-us/sql/t-sql/language-elements/case-transact-sql
There is also :case()
and maybe :switch()
could even be used as you could use the same selectors with different switches (or cases, or conds https://elixir-lang.org/getting-started/case-cond-and-if.html#cond - without adding specificity when doing so to apply some basic styles).
Then CSS is - aside transitions - not about time/timing, but declarative like say SQL. So where is the problem with when exactly sounding "time-based"? I can't follow. when
is even part of of LESS so people familiar with LESS (or guards in general) will quickly understand :when()
.
Out of the current table I like :when()
the most as the concept of guards is very close to what this new selector here should do, imho. After that I do like :also()
which could be a great name for a guarding statement in other languages as well IMHO: Match me by this function name and signature and also make sure these constraints are met.
@FremyCompany :if()
has a very procedural feel to me, next time around people try :else()
. Other than that I am with you on being close to when()
latter to me feels more like a short whenever()
in declarative languages.
CSS is - aside transitions - not about time/timing
@ionas, it wasn't, but since the same CSS Selectors Level 4 spec that we discuss here introduced Time-dimensional pseudo-classes, things became a bit more complicated. However, your other arguments for when
sound quite reasonable.
@SelenIT :if
sounds fine by me, I hadn't seen that proposal
The Working Group just discussed [selectors4] Name the "functional pseudo-class like :matches() with 0 specificity"
, and agreed to the following resolutions:
RESOLVED: Publish a new WD for Selectors adding the open items as issues.
The full IRC log of that discussion
<dael> Topic: [selectors4] Name the "functional pseudo-class like :matches() with 0 specificity"
<dael> github: https://github.com/w3c/csswg-drafts/issues/2143
<leaverou> https://github.com/w3c/csswg-drafts/issues/2143#issuecomment-360586470
<dael> leaverou: We resolved a month ago to add a pseudoclass :is . There was consern that that's logical opposite of not. Proposal is we could rename matches to is, we could rename matches, we could combine both properties. There were a bunch of proposals for different names. I made a table with proposals ^
<dael> leaverou: Hoping we could do a straw poll and decide on name.
<dael> leaverou: I think best is to mix them into one pseucoclass of :is. Matchs was impl but it's not used and is only in Safari. It is considered rude to rename.
<fantasai> I don't think we can close on this fairly in the next 4 minutes...
<fantasai> 3 minutes
<dael> florian: rude isn't the best word, but there is inertia there and it's a lot to change.
<dael> smfr: I don't have a feel for how much matches is used.
<bradk> This could be a 30 minute discussion
<dael> fantasai: We have 2 minutes. I'd like us to defer this since there has been a lot of interesting discussion. And we should have info on existance of matches.
<dael> leaverou: I won't be able to be in next week, so defer 2 weeks.
<dael> fantasai: Sure.
<dael> Rossen_: This topic will take time. Let's point everyone to the issue so it's discussed.
<dael> Rossen_: fantasai you wanted an updated WD?
<dael> fantasai: Yeah, to selectors. There's a handful of open issues that are significant and they're marked in the draft. I'd like to update the W3.org.
<dael> RESOLVED: Publish a new WD for Selectors adding the open items as issues.
<dael> Rossen_: This topic should continue being discussed in the issue and once we're ready to resolve we'll bring it back. A couple of weeks from now sounds reasonable on timeframe.
<fantasai> Issues marked in the draft: https://drafts.csswg.org/selectors-4/#issues-index
<dael> Rossen_: That's the top of the hour. Any other publication resolutions? I don't see any.
<dael> Rossen_: Let's end here.
As we're testing what's actually set or not within the pseduo-class selector I liked the idea of calling it isset
:
:isset(.foo, .bar) .baz
In terms of googling that would be easier to find than a simple :is
or :as
.
That, however, doesn't tell us that this selector is not specific, but that's a general problem of using a pseudo-class for this task I think. If more of these selectors are coming I'd prefer to see them separated into a new selector type rather than trying to fit into an existing pseudo-class system.
If we're to stick with the pseudo-class, then we could be looking at this from a functional side of things. What this selector is actually tries to do is to set a default value that can be easily overridden, so :defaults()
comes to mind.
However, there is a :default
pseudo-class and that may of course confuse people.
Left comments notifying of this issue on existing bugs for Chromium bug 568705, Firefox bug 906353, and WebKit bug 56990.
It sounds like a joke, but frankly :something()
as named by fantasai has an unexpected elegance to it; "something" is about as broad/vague as you can be... considering this is something that sets specificity to 0 (essentially canceling all specificity), I would say a broad term personifies what you're trying to do here considering the name of the subject matter at hand (specificity).
Understandably this isn't intuitive, so it most likely won't be kept, but I felt obligated to remark on the simple elegance of the temporary name.
What about the naturally related (selector selects...) :selects
?
Just a member of the community chiming in here. I think a big reason not to move off of :matches()
that hasn't been mentioned in this issue is the DOM method Element.matches()
. Developers may be familiar with _both_ the JS and CSS features, and renaming just one of them even though they serve similar purposes (with identical selector syntax) is likely to be pretty confusing.
Though I agree the :not()
vs. :is()
thing is a bit confusing, I also think there's something kind of logical about :is()
vs. :matches()
. "Is" feels like it's just the way the thing is, independent of selector logic, but "matches" feels like it kicks off a process to compute something, so the specificity rules are going to matter.
...at least that's the mnemonic _I'd_ use to teach this to new devs!
:where
is like :when
but without time connotations.
"A WHERE clause in SQL specifies that a ... statement should only affect rows that meet specified criteria." (Wikipedia)
I have added recent proposals to Lea's table.
I suggest fallback
, meaning an alternative solution when no else solution is available
or general
, which is the antonym of specific, which is then the adjective form of specificity.
Or sub
, which itself can mean a lower level or position, plus it can be an abbreviation of substitute(as in a substitute player in basketball game).
Or weak
, which means being susceptible to substitute
The Working Group just discussed Bikeshed the 0 specificity alternative to :matches()
.
The full IRC log of that discussion
<florian> Topic: Bikeshed the 0 specificity alternative to :matches()
<leaverou> Table: https://github.com/w3c/csswg-drafts/issues/2143#issuecomment-360586470
<dbaron> github: https://github.com/w3c/csswg-drafts/issues/2143#issuecomment-360586470
<florian> ericwilligers: [projets the issue]
<florian> fantasai: if we have :not and :is, they should have the same specificity
<florian> ericwilligers: matches has changed specificity recently
<florian> fantasai: that's out of scope here
<florian> ericwilligers: :when was time based, so I proposed :where, haven't heard back
<florian> astearns: does anyone have problem with :where ?
<florian> leaverou: has does that avoid the problems that :is has?
<florian> fantasai: because :is and :not need to be opposite
<florian> leaverou: how about having :is-not be the opposite of :is
<florian> all: Noooo
<florian> frremy: :where works for me
<florian> ericwilligers: has to combine well with :not()
<florian> leaverou: why can't we change :matches? it has shipped, but nobody uses it yet
<florian> astearns: we've discussed doing it several time, and failed to reach consensus
<florian> fantasai: lea propose to just change the specificity of :matches, and add a new one for the other specificity
<florian> frremy: why use the :match name at all, it's a bad name
<florian> leaverou: we're stuck with it anyway
<florian> fantasai: I want a short list so that we can think about it
<florian> leaverou: would you object to :is if it did what matches currently does, and :match() is the 0 specificity one?
<florian> fantasai: no, I would not
<florian> leaverou: what if we just have one, with an argument for specificity
<florian> fantasai: too confusing
<florian> shane: :where makes sense for people who have used SQL, but for others it is confusing, and seems to involve position
<dbaron> Whiteboard:
<florian> leaverou: I find SQL readable, but that's because it's a full sentence, which isn't the case in css
<florian> fantasai: I like 2 and 4
<Rossen> Here are the options
<dbaron> 1. :is()
<dbaron> 2. :matches() + replace existing :matches() with :is()
<Rossen> 1. :is()
<Rossen> 3. :if()
<Rossen> 4. :also()
<Rossen> 5. :where()
<florian> frremy: :and means nothing to me, all selectors already imply that
<Rossen> 6. :selects()
<florian> fantasai: yes, but :also doesn't have that implication
<florian> leaverou: in favor of :also
<florian> Rossen: [makes funny inaudible jokes]
<florian> dbaron: we have an html element called select
<florian> Rossen: let's start removing
<florian> Rossen: kill select
<florian> ericwilligers: I think we can also kill :if
<florian> Rossen: :if would need an :else
<florian> frremy: why?
<Rossen> 7. :also() + replace existing :matches() with :is()
<florian> leaverou: I'd like 7
<florian> frremy: this was called that way because the DOM API is called that
<florian> fantasai: actually, it's very old and it's the other way around
<florian> ericwilligers: it has been in webkit for a long time
<florian> astearns: how much web content uses :matches?
<florian> iank_: not a lot, looking at usecounter
<florian> ericwilligers: usecounter may be wrong
<dbaron> "the other way around" was in reference to original name being :any or :matches.
<florian> Rossen: is either 2 or 7 an option? they involve changing :matches. webkit people, can we do that?
<florian> myles: we could
<florian> myles: we would be moderately interested in updating, but it's low priority
<florian> dino: why ?
<florian> fantasai: because a best named proposal otherwise is :is, but it is bad if it's specificity doesn't match :not
<florian> fantasai: so we could change :matches to be the 0 specificity one, freeing the room for :is to do what :matches does now
<florian> leaverou: maybe we can resolve on that in parts
<florian> fantasai: removing option 1
<dbaron> I implemented :-moz-any() in Gecko in 2010 in https://bugzilla.mozilla.org/show_bug.cgi?id=544834
<florian> fantasai: the web compat impact of 2 and 7 are different
<florian> ericwilligers: does anyone want 2?
<florian> fantasai: removing 2
<florian> [lots of people]: I don't like also.
<florian> [lots of people]: [lots of jokes]
<florian> leaverou: what's wrong with :also ?
<Rossen> :soso()
<florian> dbaron: :also comes after something, but it doesn't come after anything particular
<florian> Rossen: agreed (with a pun)
<florian> ericwilligers: :where implies position OR situation
<florian> fantasai: does :where not have the same problem as :also?
<florian> fantasai: :matches does not have that problem
<florian> frremy: I prefer :where and :if, and :if makes a lot of sense when you read it
<dbaron> The thing I was talking about was called a "simple selector" in CSS 2, a "sequence of simple selectors" in selectors-3, and a "compound selector" in selectors-4.
<florian> astearns: :if clashes with JS?
<florian> [lots of people]: it doesn't
<florian> ...: :if calls for :else
<florian> ...: it doesn't
<florian> philipwalton: ??????
<florian> heycam: one option was to have a specificity parameter in :matches
<florian> astearns: we have agreed that renaming :matches is not necessary to solve this
<dbaron> s/??????/was the reason for doing this that the specificity was bad, or to give control over specificity? [answer: latter] It seems like a pseudo-class isn't the right tool for that, but I guess that's the right tool for the job./
<florian> astearns: we rejected some of the options, we should make a smaller list of plausible
<florian> fantasai: we should make a strawpoll, and then call for objections on the most popular
<florian> fantasai: :if gets 7 votes
<florian> fantasai: :also gets 1.5votes
<florian> fantasai: :where gets 7 votes
<florian> astearns: objections to :if ?
<florian> astearns: objections to :where ?
<florian> leaverou, fantasai, iank_: strong reservations
<tantek> let's strawpoll if vs where!
<florian> astearns: I am not declaring consensus
<florian> astearns: we will ask outsiders about :if vs :where
one option was to have a specificity parameter in :matches
Was the option of having one pseudo-class with optional specificity parameter (regardless its exact name), instead of two almost identical in anything except specificity pseudo-classes, rejected completely? Since the specificity rules of :matches()
have already been redefined, so compatibility with existing implementations is not required anymore, maybe this option could have a second chance?
:is()
is my favorite too.
Why not :get()
or a combination => :is-matching()
? đ
At first, I liked :where()
, but suddenly I imagined how I would interpret it if I didnât know anything about SQL, and for that moment it seemed something like :has()
: a specific element _where_, i.e. _in_ which, there is another specific element (or elements). Is it just me?
What about :zero-matches()
or :weak-matches()
?
I think it should have matches
in the name, since it does the same thing :/
:weak-matches
sounds quite straightforward to me. I like it.
I suggested fallback
and weak
in a previous comment.
If we were to add the keyword match in the pseudo-class. :match-fallbacks
, fallback-matches
are also preferred by me.
I have a strong feeling this repeats mistakes from CSS2, when pseudo-classes and pseudo-elements were the same thing syntactically (remember :after
and ::after
?). Now with introduction of functional selectors they have exactly the same syntactic form for as pseudo-classes. But when we get one more functional selector (like a negative :is
) and then another one and another one it becomes hard to distinguish ones that affect specificity and ones that do not.
@CyberAP Do you suggest we need another operator type / punctuation to describe the zero specificity pseudo-class?
@tzi, it could be anything. I think it has to be easily distinguishable from regular selectors that change specificity and be backwards compatible (not break any old css). But there has to be enough intent to do this as well because it's a big change. It all depends on whether there'll be any more functional selectors or not. There's no reason to introduce a new form of selector just for a single selector.
What about simply parentheses?
.grandfather (.parent-1, .parent-2) .child
Between :is
and :matches
, my straw poll vote goes to :is
.
How about :trivial()
:whenceforth(.foo)
Or :inasmuch-as(.foo)
Hi all,
I know that when it comes to names, we all have opinions. However, the group has been discussing this for months (possibly over a year) at this point. We've recently discussed it again in the F2F, and narrowed it down to :if()
and :where()
. I think it's highly unlikely that we will go back and reconsider other names at this point. Therefore, it would be far more productive to argue which one of these is a better choice.
Personally, I see myself using this A LOT so I think brevity is important. Roman Komarov seems to think the same. So, I would vote for :if()
. Also, I think :if()
stands much better when it's by itself than :where()
.
However, the community so far seems to favor :where(): https://twitter.com/LeaVerou/status/1014767203508338688
Based on their comments, I do worry a little that this is because they hope to see if
used for something else, or because many of them are programmers and are used to if from there (whereas if has a much stronger association with natural language, if your brain has not been tainted by programming languages).
My last two suggestions werenât serious.
But I liked :is()
more than :if()
. Sorry, but :if()
just feels wrong to me. I think for Web authors, knowing a little (or more) JavaScript is more common than not. And you donât need to know a lot of it to see if(foo) { }
as script instead of CSS. :if()
makes me expect there should also be an :else()
. Or maybe a :then()
The older proposal of @if
and @else
for media queries seemed more natural to me.
For what it's worth, languages I'm familiar with don't require an else
or then
statement for an if
, but a lot of people assume one is required because many use cases do call for one. While English and basic science class does drill into our heads that "if" statements need to be followed by "then" statements, a lot of programming syntax is counter-intuitive when compared with lexical rules. I don't see an :if
without a :then
being any more of a problem than being recalcitrant to changing :matches
while it is still in draft.
I have some mixed feelings here. In one hand, it is one of the feature that we want for like 10 years. In the other hand, I didn't read a comment from a developer that say "I don't car of the name, just ship it, we need it". Perhaps, it's because it's weird to have another operator to do almost the same thing that :matches
?
A long time ago, for every CSS developers width
was actually the content-width
. And we switch, slowy, and now we see width
as the box-width
. I see this as a great success, because it's a change of the core of CSS, that didn't introduce too much complexity, we didn't introduce a new regularly used property. We handle it like a setting, something you decide at the start of your project. Most developer adopted it, but not everybody use it, it's a choice. We could have introduce a new property like box-width
but it would have changed our daily syntax, allow mixed code, and the history of CSS would have been something hard to forget when we code.
I saw an idea of @philipwalton (https://github.com/w3c/csswg-drafts/issues/1170#issuecomment-329878248) to add an attribute on the link
tag. I think it could be a great solution.
My proposal is to add a specificity
attribute, and a value to switch the specificity of :matches()
, :not()
, and :has()
to zero. For example:
<link specificity="no-pseudo-container" rel="stylesheet" hef="path/to/reset.css">
Pros:
:matches()
is still the opposite of :not()
:matches()
and :if()
and reduce our project complexityspecificity
attribute.Cons:
:matches()
and :if()
, so no fine tuning of our selectorsWhat do you think about it, not this exact solution, but this kind of solution?
I have to say i have problem with both :if and :where cause in a bigger selector it feels like it moves the focus #select-this :if/:when(.this-is-true)
And I don't feel the same focus move from :matches, or :is. Sorry
I feel like we should probably add real-world examples and see how they fare with the most common proposals:
textarea, input:if([type=text], [type=number], [type=email]) {
/* default text box styling, with tag specificity */
/* overridden by a css class, unlike what would happen without the no-specificity attribute check */
}
a:if([href^="http"]) {
/* external link default style */
/* does not override any 'a:hover' style defined before */
}
:any-link:if(:not(:hover):not(:active):not(:focus)) {
/* by default, links have no own color */
color: inherit; outline: none;
}
:any-link:focus {
/* this rule overrides the previous one */
outline: 1px dotted currentColor;
}
:any-link:hover {
/* this rule overrides the previous ones */
color: red; outline: none;
}
vs
textarea, input:where([type=text], [type=number], [type=email]) {
/* default text box styling, with tag specificity */
/* overridden by a css class, unlike what would happen without the no-specificity attribute check */
}
a:where([href^="http"]) {
/* external link default style */
/* does not override any 'a:hover' style defined before */
}
:any-link:where(:not(:hover):not(:active):not(:focus)) {
/* by default, links have no own color */
color: inherit; outline: none;
}
:any-link:focus {
/* this rule overrides the previous one */
outline: 1px dotted currentColor;
}
:any-link:hover {
/* this rule overrides the previous ones */
color: red; outline: none;
}
:if(.class1) { ⊠}
:if(.class1.class1--optionA) { ⊠}
:if(.class2) { ⊠} /* overrides .class1.class1-optionA style */
:if(.class2.class2--optionA) { ⊠}
:if(.class2.class2--optionB) { ⊠}
vs
:where(.class1) { ⊠}
:where(.class1.class1--optionA) { ⊠}
:where(.class2) { ⊠} /* overrides .class1.class1-optionA style */
:where(.class2.class2--optionA) { ⊠}
:where(.class2.class2--optionB) { ⊠}
Typing it out, I think :if
is the best solution by far. I only had a very slight preference for :if
during the meeting, and voted for both proposals, but after seeing this, I'm strongly in favor of :if
now.
And what about a :0()
selector?
It's actually mean that it does something special. The zero is not explicit, but it is at least logical.
a:0([href^="http"]) {
/* external link default style, does not override any 'a:hover' styles */
}
:0(.block) {
/* opting out of specificity entirely */
}
Cheers,
Thomas.
Love the :0
idea, a nice smiley => :0
=> OMG, specificity to 0 ???? :D
For me the problem with :if
is not that it needs an :else
. Instead it's that intuitively I would think it would remove part of the selector if a condition is false, i.e. foo bar:if(#cond) baz
would behave like foo bar#cond baz, foo baz
.
Of course this doesn't really make sense, but it's what the selector seems to mean to me at first glance.
I don't really like :where
either.
:0
is not intuitive, it would be difficult to find its meaning using a search engine, and would require syntax changes because identifiers cannot begin with a digit.
:0()
is one of the best idea so far. As identifiers cannot begin with a digit, what about :zero()
or :void()
or even :null()
(even if I don't like this one)?
@LeaVerou
:if
has a strong procedural meaning whereas :where
has not and I share your fear that :if
may or may not become useful for other purposes in future.
@CyberAP
... from a functional side of things. What this selector ... tries to do is to set a default value that can be easily overridden, so :defaults() comes to mind.
However, there is a :default pseudo-class and that may of course confuse people.
What about :init()
or :initial()
then. It behaves similiar to resetting a bunch of values to property: initial
.
a:initial(.toggled) {
/* external link default style, does not override any 'a:hover' styles */
}
Edit:
:cond(...)
> :where(...)
> :initial(...)
> :when(...)
> :specificity(0, ...)
> :for()
> :if(...)
Edit: Fixed example @tzi
Hmm, what about :foreach
? It basically takes an array of arguments and for each item performs some operation, without affecting anything, similar to the forEach
array method in JS.
So if with JS we would write:
['.a', '.b', '.c'].forEach(item => doSomething(item + ' el'));
In CSS it would become:
:foreach(.a,.b,.c) el {
// doSomething
}
I'm still fond of :is()
because of the brevity and clarity, but if that's been decided against would a name like :selector()
be a good replacement? Something like :selector()
indicates to me that it would match a CSS selector, and when styled like a pseudo-class (:()
) it can modify any part of a selector as well. Here are some examples so you can see what it might look like and how it reads in code:
a:selector(.active) { }
:selector(header, footer, nav) a { }
It's not explicit that it's ignoring specificity, but it seems less permanent, or less strong than if I had written the same selector directly. What do you think?
What about :and()
? It's short, it seems intuitive (a conjunction of two conditions, the target element should match both main _and_ additional part), but in the same time it separates the selector into the non-parenthesized and parenthesized parts, implying that the latter is "special" (so its specificity might
be not counted as usually).
Though it might look a bit odd in the beginning of the selector, the general rule that absence of the elemental selector means *
should help to understand the intent to express the selector that has the specificity of the universal selector (i.e. zero) _and_ still selects only specific elements...
@SelenIT :and()
can be confused with a comma combinator a, b
.
What about :any
? It's short, intuitive, and it's already implemented (but with a prefix and specificity 0,1,0 instead of 0,0,0).
There are also some old documentations mentioning :any
, so people may get confused about :any
, :matches
and :something
. Renaming :something
to :any
reduces the cognitive load, it's one option less to remember. Sure, if some documentation mentioned the specificity of :any
then it will become invalid, but usually the focus was in the functionality instead of the specificity.
@CyberAP, the comma clearly means "or", not "and" :)
@Loirooriol, wouldn't it _increase_ the cognitive load instead if for some period of transition there would co-exist two completely different experimental implementations of :any
/:-*-any
â the old deprecated one with the specificity of the single pseudo-class and the new one with no specificity at all?
But I agree that it's confusing to have several things that effectively do nearly the same job, but _a bit_ differently. That's why, ideally, I would prefer the _single_ pseudo-class with some (optional) modifier for turning off/adjusting the specificity to the current solution with 2 very similar pseudo-classes (plus the old deprecated-but-yet-supported one).
I've been hesitant to comment because I've not had anything particularly thoughtful to add beyond varying degrees of conflicting thoughts on each one. However, over the past week or so I have informally talked to a (small) number of people with various degrees of skill who either independently arrived at :zero(...)
or :nil(...)
when posed the description without options, or, having known options agreed that this is among the better ones in this thread.
I just want to note that is isn't in the table above and I am in that camp, I think that either of those makes more sense to me than many of the others and I think the big strike against it in terms of the table is that it would prevent from later extending it to be arbitrary specificity. I'm not entirely convinced that is actually a big strike though.
TL;DR: I like :any()
.
Forking @LeaVerouâs list from earlier to express sentiments on keywords I was drawn to:
| Name | Pros | Cons |
| --- | --- | --- |
| :any()
| short, meaningful | prefixed version had differing specificity characteristics |
| :as()
| short, frequently used | suggests transformation of preceeding selector |
| :if()
| short | suggests logical opposite of non-existent :else()
|
| :is()
| short, meaningful, backronym for "_Ignore Specificity_". | suggests logical opposite of existing :not
without matching specificity characteristics |
| :nil()
| short | infrequently used in language, explicitly not extendable |
| :nospecificity()
| meaningful | long, explicitly not extendable |
| :when()
| meaningful | suggests a change of context (when some time is.., when some element query is...) |
| :zero()
| meaningful | explicitly not extendable |
* The table is sorted alphabetically by name
* _nil_ is an infrequent word according to https://www.wordfrequency.info/free.asp?s=y
Forking @FremyCompanyâs usages with minor changes to further share my impressions:
/* :any() â actually looks okay especially because any is also used in any-link */
:any(textarea, input:matches([type=text], [type=number], [type=email], :not([type])) {
/* weightless text box styling */
}
:any(:any-link:not(:hover):not(:active):not(:focus)) {
/* weightless link styling */
}
/* :as() â looks visually similar to :has and tripped me up when following it with :any-link */
:as(textarea, input:matches([type=text], [type=number], [type=email], :not([type])) {
/* weightless text box styling */
}
:as(:any-link:not(:hover):not(:active):not(:focus)) {
color: inherit;
}
/* :if() â so is :else like :not but with zero-specificity? */
:if(textarea, input:matches([type=text], [type=number], [type=email], :not([type])) {
/* weightless text box styling */
}
:if(:any-link:not(:hover):not(:active):not(:focus)) {
/* weightless link styling */
}
/* :nil() â i get it, but looks like programmer-speak not found elsewhere in css */
:nil(textarea, input:matches([type=text], [type=number], [type=email], :not([type])) {
/* weightless text box styling */
}
:nil(:any-link:not(:hover):not(:active):not(:focus)) {
/* weightless link styling */
}
/* :nospecificity() â hello, spell check, my old friend */
:nospecificity(textarea, input:matches([type=text], [type=number], [type=email], :not([type])) {
/* weightless text box styling */
}
:nospecificity(:any-link:not(:hover):not(:active):not(:focus)) {
/* weightless link styling */
}
/* :when() â it feels like this should not take css selectors */
:when(textarea, input:matches([type=text], [type=number], [type=email], :not([type])) {
/* weightless text box styling */
}
:when(:any-link:not(:hover):not(:active):not(:focus)) {
/* weightless link styling */
}
/* :zero() â it feels like :zero is supposed to represent a state */
:zero(textarea, input:matches([type=text], [type=number], [type=email], :not([type])) {
/* weightless text box styling */
}
:zero(:any-link:not(:hover):not(:active):not(:focus)) {
/* weightless link styling */
}
My overall impression is that :any
seems the most clear and consistent.
Is :matches(0, selector, selector...))
not an option?
@jonathantneal I don't see the cons about a pseudo-class that is "explicitly not extended-able". Can you give some context?
:nil()
and :zero()
seems to be the only ones where it will be clear "why we used this pseudo-selector". So they've got my vote.
Hey @tzi, I was under the impression that folks wanted the ability to possibly extend the functionality of this selector in the future. I considered âexplicitly not extendableâ to be taken similarly as one of Leaâs cons â â_can't be extended to specify specificity_â. Sorry if I missed that this concern is no longer relevant.
@ionas, Iâm not opposed to extending matches, either, especially if itâs readable and doesnât require look-ahead. Thanks for looking at it anyway. đ
Most of the comments from the last three weeks seem to not respect the fact that the WG has narrowed their choices down to :if
and :where
.
Until we see implementation, @Tyler-H, I would actively encourage you to challenge any consensus you think could be better. Make your differing evaluation clear. Keep a positive tone. Thatâs showing respect for the web _and_ the people who make it.
get it wrong & it's on the web & pissing off devs forever
â Bruce Lawson https://twitter.com/brucel/status/1022394427225063425
@jonathantneal The thing is this topic has been taken to the bike shed already, and Lea requested to focus discussion on the two WG front-runners. Ignoring the request without providing critiques of the front-runners is not respect, it's... ignoring the request. Only two or three comments have provided concerns/critiques with the front-runners, while others (like yours) just take other suggestions and run with them.
As far as "pissing off devs forever" frankly the concerns of people who have visceral reactions to naming things should have their concerns notched far below those with actual logic-based reasons.
Iâm legitimately (and not sarcastically) sorry to you if my critique was not profound enough, but please do re-read my post, looking specifically for :if()
.
All of that aside, if you wish to continue bikeshedding how we ought to bikeshed, I would kindly ask that we move _that_ discussion to Twitter, where civilized discourse may abound. đ
:nil()
and:zero()
seems to be the only ones where it will be clear "why we used this pseudo-selector". So they've got my vote.
@tzi - and :nospecificity
@Tyler-H FWIW, while I definitely share the sentiment that perpetual bikeshed isn't a good thing, it seems to me that part of why the WG has made no real decision is that none of the options seemed particularly great (at least this has been my feeling - kind of noncommittal/least worst). Since then, I feel like some options that seem at least as good have been added. From other conversations I am led to think that perhaps some other WG members feel this. I think that updating the table and asking whether it is more valuable for the pseudo to be clear or extendable to including a numeric specificity seems valid and potentially helpful. Perhaps the WG can resolve one way or another on that much at least and we can eliminate several items?
I've read the whole thread, and I'm aware of that now it's supposedly only an :if
vs. :when
question. But I'd like to get back a little bit (if only to show why :if
and :when
are mistaken tracks).
It's notable how far we've got from :is
. :is
is by far the most intuitive choice, everybody gets that in their mind in the first (or second) place, and there's a reason for that (no, not the funny acronym, which in my view has zero relevance). A selector, by nature, is a predicate, which says something about the matching element. Linguistically, nouns, adjectives and verbs and negation play well as predicates. Not surprisingly, if we look around among the current pseudo-classes, we find exactly these word classes. Any other word class, which the alternatives belong to, including :if
, :when
, :nospecificity
, :zero
etc., essentially breaks this logic and so hits a little bit in the gut. Obviously they can been read as parts of a sentence, but the reading logic is custom in that case. :if
is not really a first-order predicate in itself.
Now came the problem with the imperfect contrast with :not
. I'm not sure how this can be more important, than the above. :is
is an exception in the system which has no specificity calculation, and having the most generic name plays well with this fact. Technically this imperfect contrast is not a problem at all. It's actually beneficial, because it makes :is(:not(
meaningful, and it reads well.
On the other hand, in the future, other strategies might appear for specificity management. To me, for example, using the zero-specificity selector (whatever name it has, and however short it is) extensively, particularly with wrapping the whole selector to keep it on zero, is not a good long-term solution. It's just code repetition. We might have a higher order scope for specificity, maybe something like this:
<link rel="stylesheet" type="text/css" href="framework.css" specificity=1>
<link rel="stylesheet" type="text/css" href="mycustom.css" specificity=x>
which might act as the highest order in the calculation placeholders: x,0,0,0. I know it's out of scope (and maybe it is proposed already?), but my point is that specificity strategies can easily evolve above the selector level, so we shouldn't get lost in the supposed significance of the :is
vs. :not
question. IMO, :is
would nicely fill a gap in the API (linguistically) and the zero-specificity function is just a good motive to get it not just as an alias (to :matches
). Imperfect contrast with :not
is not a problem at all. And we can leave :matches
as it is now.
Sorry for being too long.
I mentioned this during the meeting and I'll repeat, I think it's important for this selector to be short and also for it to be clear about how it's different from :matches()/:not()
. Subtly different names that imply subtly different behavior without actually implying the difference through their names are very confusing.
I'm rather less concerned about extending to an arbitrary specificity level, it's reasonably likely that we never do that. Numbers for ordering are not the best, see e.g. BASIC and its goto statements, or tabindex if you want a more recent example. Ideally any solutions to specificity wrangling would incorporate some concept of higher level structures rather than numbers on the number line.
:zero()
and :nil()
aren't great in many ways, but at least they fulfill the two criteria I mentioned: they're short, and they imply something about what makes them different from :matches()
/:not()
. Or :is()/:not()
if we lived in an ideal world and could rename :matches()
. :)
The CSS Working Group just discussed [selectors4] Name the âfunctional pseudo-class like :matches() with 0 specificityâ
.
The full IRC log of that discussion
<mstange> Topic: [selectors4] Name the âfunctional pseudo-class like :matches() with 0 specificityâ
<mstange> fantasai: Lea is not here, do we want to talk about it?
<mstange> fantasai: Anybody have anything to add to this discussion? There's no clear "this is definitely what we should do" resolution.
<TabAtkins> New suggestion: smoosh()
<Rossen> github: https://github.com/w3c/csswg-drafts/issues/2143
<fantasai> https://github.com/w3c/csswg-drafts/issues/2143#issuecomment-408128027
<TabAtkins> Sorry, :smoosh()
<zcorpan> -webkit-appearance: smoosh
<mstange> fantasai: This takes a list of selectors of which any can match. Unlike the :matches selector it basically zeroes out the specificity: anything you put inside has a specificity of zero.
<mstange> fantasai: This gives you more control about which parts of the selector affect the specificity and which down.
<mstange> fantasai: The only question is what to name it.
<mstange> fantasai: Some of the suggestions didn't get any traction.
<mstange> fantasai: We don't have any suggestion that is clearly better than the other ones.
<mstange> fantasai: My concern with a lot of these is that it is not very clear for :if or :where why this is different from :matches.
<mstange> ... It's different because of the zero specificity, so the name should have something to do with that.
<mstange> franremy: Last time we had narrowed it down to three.
<mstange> fantasai: New ones were added after last time.
<mstange> franremy: We almost agreed on one of them last time, don't remember which one.
<mstange> franremy: Would prefer to not expand the length of the list of candidates.
<mstange> dbaron: To make progress, we need to say "Nobody leaves the room until we decide."
<ericwilligers> Last time: if vs where
<fantasai> https://lists.w3.org/Archives/Public/www-style/2018Jul/0027.html
<mstange> fantasai: Our resolution last time was to narrow the short list to :if and :where, and we added :nil and :zero.
<mstange> ... So we could choose between those.
<mstange> Rossen: if, where, nil, zero, quash
<mstange> Rossen: In that order, with if being 1 and quash being 5, go ahead and put in your preferred 3.
<mstange> ... In the order of preference
<fantasai> 1 = if, 2 = where, 3 = nil, 4 = zero, 5 = quash
<franremy> 1 2 ... 4 3 5
<iank_> 2, 5, 3
<fantasai> 5, 3, 4, 1, 2
<cbiesinger> 2, 1
<florian> 1, 2
<TabAtkins> 3, 2, 1
<heycam> 2, 1
<futhark> 2 3 5
<dbaron> 4 3 2 5 1
<fantasai> https://github.com/w3c/csswg-drafts/issues/1170
<ericwilligers> 2, 1, 4
<Rossen> 2, 1
<eae> 3 2 1
<melanierichards> 2
<AmeliaBR> 2 4
<tantek> 4 3 5 :ns (no specificity)
<rachelandrew> 2, 1 , 3
<emilio> 3, 1
<Oriol> 1, 2, 4, but I would prefer any
<emilio> fantasai: lol
<bz> nsISelector
<bz> That's NS
<mstange> Rossen: A lot of votes for number 2 as the first choice
<AmeliaBR> Why was :is
dropped from the options?
<mstange> ... Resolve on :where?
<mstange> ... If anyone has a strong reason to change this, speak up now.
<mstange> Resolved: Name the selector :where
:zero()
and:nil()
aren't great in many ways, but at least they fulfill the two criteria I mentioned: they're short, and they imply something about what makes them different from:matches()
/:not()
. Or:is()/:not()
if we lived in an ideal world and could rename:matches()
. :)
@fantasai We may not live in an ideal world, but I think we do live in one that's close enough to introduce :is()
and redefine :matches()
as a deprecated alias of it. What do you think?
@gibson042 Filed https://github.com/w3c/csswg-drafts/issues/3258 on renaming :matches() to :is(). If anyone has an opinion on it, please comment there.
TLDR: Thank you so much
I predict :where()
will lead to a new enlighten age of reset/base, classless, css libraries like https://github.com/mblode/marx and similar. In conjunction with the data attribute and other attribute selectors there will be a trove of options now to reset stuff without doing ANY harm.
I love that the WG got through with it eventually and even picked a declarative/functional/semantic name (where over nil). There will be new reset stylesheets that won't interfere with any specificy issues and we will finally have a nice base to cover all different browsers and OS platforms. Obviously properties that affect form widgets (like appearance), outlines, highlights, scrollbars, overscrolling/touch etc. are now things that need to be resolved as quickly as possible so that it becomes easy to reset everything, or - everything but form controls, scrollbars, overscrolling etc.
Thank you so much (:is() will follow as an alias of :matches() and sanity returns)
Most helpful comment
I'm for
:is()
, as it:is()
easy to memorize as kind of acronym for "Ignore Specificity" :)