Closed fantasai closed 5 years ago
: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()
.
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”
.
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 andfilter
s a property might be confusing, and that:nospecificity()
is a pain to type. Additional suggestions, comments, and clarifications welcome.