Skip to content
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

[selectors4] Name the “functional pseudo-class like :matches() with 0 specificity” #2143

Closed
fantasai opened this issue Dec 28, 2017 · 103 comments
Closed

Comments

@fantasai
Copy link
Collaborator

@fantasai fantasai commented Dec 28, 2017

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.

@LeaVerou
Copy link
Contributor

@LeaVerou LeaVerou commented Dec 28, 2017

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.
@SebastianZ
Copy link
Contributor

@SebastianZ SebastianZ commented Dec 29, 2017

: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

@SelenIT
Copy link
Collaborator

@SelenIT SelenIT commented Dec 29, 2017

I'm for :is(), as it :is() easy to memorize as kind of acronym for "Ignore Specificity" :)

@Loirooriol
Copy link
Collaborator

@Loirooriol Loirooriol commented Dec 29, 2017

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.

@SelenIT
Copy link
Collaborator

@SelenIT SelenIT commented Dec 30, 2017

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.

@Loirooriol
Copy link
Collaborator

@Loirooriol Loirooriol commented Dec 30, 2017

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.

@fantasai
Copy link
Collaborator Author

@fantasai fantasai commented Jan 1, 2018

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.

@Loirooriol
Copy link
Collaborator

@Loirooriol Loirooriol commented Jan 1, 2018

What about swapping :is and :matches, then? So :is would be analogous to :not and :matches would have 0 specificity.

@SelenIT
Copy link
Collaborator

@SelenIT SelenIT commented Jan 2, 2018

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?

@LeaVerou
Copy link
Contributor

@LeaVerou LeaVerou commented Jan 2, 2018

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).

@SelenIT
Copy link
Collaborator

@SelenIT SelenIT commented Jan 2, 2018

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?

@tabatkins
Copy link
Member

@tabatkins tabatkins commented Jan 2, 2018

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.

@inoas
Copy link

@inoas inoas commented Jan 3, 2018

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:

  • If :not() and :matches() are the inverse of each other they should have inversed names for easy understanding and usage.
  • If :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):

  • A) Rename matches() to is() - use matches() for the new 0-specificity feature discussed here.
  • B) Alias 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?

@inoas
Copy link

@inoas inoas commented Jan 3, 2018

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:

  1. Use matches() for the new implementation and rename current matches() implementation in the wild to is() - Issue: Vendor Safari has to adapt.
  2. Use when() for the new implementation and alias current matches() to is() and deprecate matches() - Issue: None?
  3. Use 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()
@tabatkins
Copy link
Member

@tabatkins tabatkins commented Jan 3, 2018

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.

@SelenIT
Copy link
Collaborator

@SelenIT SelenIT commented Jan 3, 2018

@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.

@LeaVerou
Copy link
Contributor

@LeaVerou LeaVerou commented Jan 3, 2018

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.

@fantasai
Copy link
Collaborator Author

@fantasai fantasai commented Jan 3, 2018

@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).

@tabatkins
Copy link
Member

@tabatkins tabatkins commented Jan 3, 2018

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.

@inoas
Copy link

@inoas inoas commented Jan 3, 2018

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
Copy link
Contributor

@LeaVerou LeaVerou commented Jan 3, 2018

@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.

@fantasai
Copy link
Collaborator Author

@fantasai fantasai commented Jan 4, 2018

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.

@Nadya678
Copy link

@Nadya678 Nadya678 commented Jan 7, 2018

Should the :is() have specificity like :not()?
What specificity has :has()?

@ewilligers
Copy link
Contributor

@ewilligers ewilligers commented Jan 7, 2018

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.

fantasai added a commit that referenced this issue Jan 16, 2018
@fantasai
Copy link
Collaborator Author

@fantasai fantasai commented Jan 16, 2018

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().

@fantasai
Copy link
Collaborator Author

@fantasai fantasai commented Jan 16, 2018

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.

@tabatkins
Copy link
Member

@tabatkins tabatkins commented Jan 16, 2018

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.

@tomhodgins
Copy link

@tomhodgins tomhodgins commented Jul 13, 2018

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?

@SelenIT
Copy link
Collaborator

@SelenIT SelenIT commented Jul 13, 2018

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...

@CyberAP
Copy link

@CyberAP CyberAP commented Jul 13, 2018

@SelenIT :and() can be confused with a comma combinator a, b.

@Loirooriol
Copy link
Collaborator

@Loirooriol Loirooriol commented Jul 13, 2018

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.

@SelenIT
Copy link
Collaborator

@SelenIT SelenIT commented Jul 13, 2018

@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).

@bkardell
Copy link
Contributor

@bkardell bkardell commented Jul 17, 2018

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.

@jonathantneal
Copy link
Contributor

@jonathantneal jonathantneal commented Jul 26, 2018

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

Example Usages:

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.

@phistuck
Copy link
Contributor

@phistuck phistuck commented Jul 26, 2018

Is :matches(0, selector, selector...)) not an option?

@tzi
Copy link

@tzi tzi commented Jul 26, 2018

@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.

@jonathantneal
Copy link
Contributor

@jonathantneal jonathantneal commented Jul 26, 2018

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. 😄

@Tyler-H
Copy link

@Tyler-H Tyler-H commented Jul 26, 2018

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.

@jonathantneal
Copy link
Contributor

@jonathantneal jonathantneal commented Jul 26, 2018

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

@Tyler-H
Copy link

@Tyler-H Tyler-H commented Jul 26, 2018

@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.

@jonathantneal
Copy link
Contributor

@jonathantneal jonathantneal commented Jul 26, 2018

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. 😄

@bkardell
Copy link
Contributor

@bkardell bkardell commented Jul 26, 2018

: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?

@sarimarton
Copy link

@sarimarton sarimarton commented Aug 1, 2018

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.

@fantasai
Copy link
Collaborator Author

@fantasai fantasai commented Oct 23, 2018

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(). :)

@css-meeting-bot
Copy link
Member

@css-meeting-bot css-meeting-bot commented Oct 23, 2018

The CSS Working Group just discussed [selectors4] Name the “functional pseudo-class like :matches() with 0 specificity”.

  • RESOLVED: Name the selector :where
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//issues/2143
<fantasai> https://github.com//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//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
ewilligers pushed a commit to ewilligers/csswg-drafts that referenced this issue Oct 23, 2018
The functional pseudo-class like :matches() with 0 specificity
is named :where().
w3c#2143 (comment)

resolves w3c#2143
fantasai added a commit that referenced this issue Oct 23, 2018
The functional pseudo-class like :matches() with 0 specificity
is named :where().
#2143 (comment)

resolves #2143
jonathantneal referenced this issue in csstools/cssdb Oct 23, 2018
@gibson042
Copy link

@gibson042 gibson042 commented Oct 27, 2018

: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?

@fantasai
Copy link
Collaborator Author

@fantasai fantasai commented Oct 27, 2018

@gibson042 Filed #3258 on renaming :matches() to :is(). If anyone has an opinion on it, please comment there.

@inoas
Copy link

@inoas inoas commented Oct 28, 2018

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

You can’t perform that action at this time.