New issue

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

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

Already on GitHub? Sign in to your account

[selectors] Functional pseudo-class like :matches() with 0 specificity #1170

Closed
LeaVerou opened this Issue Apr 5, 2017 · 50 comments

Comments

Projects
None yet
@LeaVerou
Contributor

LeaVerou commented Apr 5, 2017

The problem

Sometimes, specificity is a blessing. However, more often than not, it gets in the way, and authors have to resort to hacks in order to artificially adjust specificity, such as repeating classes (.foo.foo.foo), turning id selectors to attribute selectors ([id=foo] instead of #foo), or adding pointless :not()s (e.g. .foo:not(.enough):not(.specificity)).

A common example where specificity goes against author intent is :not(). The default specificity rules on :not() are almost never helpful. One often includes lots of filters, one after the other, but that increases specificity and makes these rules hard to override. E.g. good luck overriding div:not(#foo):not(#bar):not(#baz) in a sane way, even though this selector is essentially as general as div minus three specific divs.

In the last few years, it has even become common to avoid selector logic altogether, just to avoid specificity woes. This is basically what conventions like BEM are all about: turning combinators and pseudo-classes into a single class selector so that every selector has the same specificity and the cascade only goes top to bottom. For example, authors would write .form__input--disabled instead of form input[disabled].

Specificity becomes an even bigger problem when authoring UI libraries, where you want your styles to be easy to override by the end author without them having to keep up with your stylesheet, but you still want to provide sensible defaults. The default Mavo stylesheet has many good examples of this. It's a stylesheet that's meant to be easy to override, and in practice, authors have to artificially increase specificity of their rules to override it because I had to be very conservative in what is styled so the selectors have to be very specific. However, being specific doesn't always mean they are high priority.

All in all, specificity is a heuristic. It's assuming that it can deduce rule priority from the selection logic, but the selector is not really expressing priority, it's expressing a query. Heuristics are very helpful when they are correct, but a PITA when they fail, so there always needs to be a way to override them. Especially in this case, specificity is a heuristic that fails so often that many authors have decided the benefit they get from selectors is not worth the specificity trouble and prefer to ditch selectors altogether and just use classes + JS for the querying logic!

Proposed solution

A new pseudo-class (name TBB, perhaps :filter()?) that works exactly like :matches() but with zero specificity. That way, authors have control over the specificity of their rules, and can choose what is best for their use case.

Or, even :matches() itself, since it has not yet been implemented, and changing its specificity would solve #1027 at once.

Edited on Sep 15 to add :filter() and some more thoughts

@LeaVerou LeaVerou added the selectors-4 label Apr 5, 2017

@LeaVerou LeaVerou changed the title from [selectors-4] Functional pseudo-class like :matches() with 0 specificity to [selectors] Functional pseudo-class like :matches() with 0 specificity Apr 14, 2017

@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou
Contributor

LeaVerou commented Apr 14, 2017

@FremyCompany

This comment has been minimized.

Show comment
Hide comment
@FremyCompany

FremyCompany Apr 16, 2017

Contributor

cc @gregwhitworth who is a long-proponent of a similar solution.

I was initially skeptical but then found some cases where this would be useful; all in all I would be in favor of such a change to :matches.

FWIW one such example is that sometime you need to apply some form of css reset for an element to work properly (because it comes from another framework and doesn't like the fact you override flex-direction to column by default for all elements) so you want to unset flex-direction again inside that element but doing so means that the reset will override any selector targeting the content of the element if its selector is less specific than the selector you use to target the reset root.

Contributor

FremyCompany commented Apr 16, 2017

cc @gregwhitworth who is a long-proponent of a similar solution.

I was initially skeptical but then found some cases where this would be useful; all in all I would be in favor of such a change to :matches.

FWIW one such example is that sometime you need to apply some form of css reset for an element to work properly (because it comes from another framework and doesn't like the fact you override flex-direction to column by default for all elements) so you want to unset flex-direction again inside that element but doing so means that the reset will override any selector targeting the content of the element if its selector is less specific than the selector you use to target the reset root.

@SelenIT

This comment has been minimized.

Show comment
Hide comment
@SelenIT

SelenIT Apr 17, 2017

Collaborator

Or, even :matches() itself, since it has not yet been implemented

What's wrong with WebKit's implementation of :matches()?

Collaborator

SelenIT commented Apr 17, 2017

Or, even :matches() itself, since it has not yet been implemented

What's wrong with WebKit's implementation of :matches()?

@bkardell

This comment has been minimized.

Show comment
Hide comment
@bkardell

bkardell Sep 15, 2017

I think about this nearly every single day. Agree this would be worth doing!

bkardell commented Sep 15, 2017

I think about this nearly every single day. Agree this would be worth doing!

@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou

LeaVerou Sep 15, 2017

Contributor

(For those wondering where my comment went, I integrated it into the first post and then deleted it)

Contributor

LeaVerou commented Sep 15, 2017

(For those wondering where my comment went, I integrated it into the first post and then deleted it)

@studiosciences

This comment has been minimized.

Show comment
Hide comment
@studiosciences

studiosciences Sep 15, 2017

I have a component with a lot of states, but I want to have a single class. I do this with data attributes now, but it increases specificity. Currently it's something like this (Suggest naming this :is)...

.button {
    ...styles 

    &:is([data-size=small]) {
        ...styles
    } 
    &:is(:focus) {
        ...styles
    }
    &:is([disabled]) {
        ...styles
    }
    &:is([data-selected]) {
        ...styles
    } 
}

studiosciences commented Sep 15, 2017

I have a component with a lot of states, but I want to have a single class. I do this with data attributes now, but it increases specificity. Currently it's something like this (Suggest naming this :is)...

.button {
    ...styles 

    &:is([data-size=small]) {
        ...styles
    } 
    &:is(:focus) {
        ...styles
    }
    &:is([disabled]) {
        ...styles
    }
    &:is([data-selected]) {
        ...styles
    } 
}
@tabatkins

This comment has been minimized.

Show comment
Hide comment
@tabatkins

tabatkins Sep 15, 2017

Member

I'm convinced by this reasoning; in particular, that "div, but minus these three specific ones" should be capable of being overridden reasonably, instead of blowing up to a 3-ID specificity.

Do we want to stick with this "something that makes its contents specificity-0", or try and generalize this to solve specificity hacks more generally? I'm not 100% sure how we'd do the latter in a future-friendly way (we've gone back and forth with precisely how many categories are in "specificity"), but I guess just sticking with the Big Three would be fine. (When we've tried to insert something else, it's for significant semantic differences, like scoped vs not, or inline vs not.)

Hmm. If we simplify and say that it has to be a compound selector only, then the grammar's pretty easy; if you want more complexity, you just nest a :matches() in. I think I'm in favor of the simple, short :is() naming, as this is more-or-less a no-op wrapper; every selector is an "is" filter already. Then you could control specificity like :is(.foo, 1 2 3) to give it the specificity of 1 ID, two attrs, and 3 tagnames. Leaving the specificity off defaults it to 0 0 0.

(I suppose we could allow a full complex selector, as commas don't interfere with that, and just require :matches() if you want a selector list. But maybe good to keep it simple - it's just a modifier to a single selector. We let you do a full compound selector, rather than limiting to a single simple, to avoid verbosity in a common case - .foo:is(.bar):is(.baz) is identical in meaning to .foo:is(.bar.baz), no reason to require more parens than necessary there.)

Member

tabatkins commented Sep 15, 2017

I'm convinced by this reasoning; in particular, that "div, but minus these three specific ones" should be capable of being overridden reasonably, instead of blowing up to a 3-ID specificity.

Do we want to stick with this "something that makes its contents specificity-0", or try and generalize this to solve specificity hacks more generally? I'm not 100% sure how we'd do the latter in a future-friendly way (we've gone back and forth with precisely how many categories are in "specificity"), but I guess just sticking with the Big Three would be fine. (When we've tried to insert something else, it's for significant semantic differences, like scoped vs not, or inline vs not.)

Hmm. If we simplify and say that it has to be a compound selector only, then the grammar's pretty easy; if you want more complexity, you just nest a :matches() in. I think I'm in favor of the simple, short :is() naming, as this is more-or-less a no-op wrapper; every selector is an "is" filter already. Then you could control specificity like :is(.foo, 1 2 3) to give it the specificity of 1 ID, two attrs, and 3 tagnames. Leaving the specificity off defaults it to 0 0 0.

(I suppose we could allow a full complex selector, as commas don't interfere with that, and just require :matches() if you want a selector list. But maybe good to keep it simple - it's just a modifier to a single selector. We let you do a full compound selector, rather than limiting to a single simple, to avoid verbosity in a common case - .foo:is(.bar):is(.baz) is identical in meaning to .foo:is(.bar.baz), no reason to require more parens than necessary there.)

@philipwalton

This comment has been minimized.

Show comment
Hide comment
@philipwalton

philipwalton Sep 15, 2017

Member

Do we want to stick with this "something that makes its contents specificity-0", or try and generalize this to solve specificity hacks more generally?

I'm in favor of a generalized approach.

What about something that just turns off specificity at the stylesheet level, and for those stylesheets everything is order based? This would allow authors to easily control when they wanted specificity to work as an override and when they wanted to ignored it and treat it purely as a query.

This would also help with resets and third-party stylesheets, and make it much easier for them to never clash with first-party styles.

Maybe something like:

<link nospecificity rel="stylesheet" hef="path/to/reset.css">
Member

philipwalton commented Sep 15, 2017

Do we want to stick with this "something that makes its contents specificity-0", or try and generalize this to solve specificity hacks more generally?

I'm in favor of a generalized approach.

What about something that just turns off specificity at the stylesheet level, and for those stylesheets everything is order based? This would allow authors to easily control when they wanted specificity to work as an override and when they wanted to ignored it and treat it purely as a query.

This would also help with resets and third-party stylesheets, and make it much easier for them to never clash with first-party styles.

Maybe something like:

<link nospecificity rel="stylesheet" hef="path/to/reset.css">
@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou

LeaVerou Sep 15, 2017

Contributor

@tabatkins
Interesting idea, certainly more readable than current specificity hacks!
However, I wonder if it would be better to add single-argument :is() to level 4 and extend to allow for a second argument in Level 5? I'm a bit concerned that the extra functionality might slow down implementations, and since selectors don't fall back as gracefully as other unsupported CSS features, adoption will be slow anyway.

Contributor

LeaVerou commented Sep 15, 2017

@tabatkins
Interesting idea, certainly more readable than current specificity hacks!
However, I wonder if it would be better to add single-argument :is() to level 4 and extend to allow for a second argument in Level 5? I'm a bit concerned that the extra functionality might slow down implementations, and since selectors don't fall back as gracefully as other unsupported CSS features, adoption will be slow anyway.

@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou

LeaVerou Sep 15, 2017

Contributor

What about something that just turns off specificity at the stylesheet level, and for those stylesheets everything is order based? This would allow authors to easily control when they wanted specificity to work as an override and when they wanted to ignored it and treat it purely as a query.

While something like this could be useful in some cases (as you mention, resets are a prime candidate), I'm not sure it should be the only way to override the specificity heuristic. Specificity can be a useful concept, it's just that the inferred specificity is often wrong.

Also, you don't want any author rule to be able to override any rule in the third-party stylesheet. E.g. your library may have a .button component, you don't want their div or even * rule to override that, otherwise it becomes impossible to style anything.

Contributor

LeaVerou commented Sep 15, 2017

What about something that just turns off specificity at the stylesheet level, and for those stylesheets everything is order based? This would allow authors to easily control when they wanted specificity to work as an override and when they wanted to ignored it and treat it purely as a query.

While something like this could be useful in some cases (as you mention, resets are a prime candidate), I'm not sure it should be the only way to override the specificity heuristic. Specificity can be a useful concept, it's just that the inferred specificity is often wrong.

Also, you don't want any author rule to be able to override any rule in the third-party stylesheet. E.g. your library may have a .button component, you don't want their div or even * rule to override that, otherwise it becomes impossible to style anything.

@SelenIT

This comment has been minimized.

Show comment
Hide comment
@SelenIT

SelenIT Sep 15, 2017

Collaborator

Speaking about current specificity hacks, in CSS Selectors 4 there is already a way to build complex selectors with the specificity of a single class using nested :not() pseudo-classes (proposed by @kizu and proven to work in WebKit). Maybe it could be useful as a reference?

Collaborator

SelenIT commented Sep 15, 2017

Speaking about current specificity hacks, in CSS Selectors 4 there is already a way to build complex selectors with the specificity of a single class using nested :not() pseudo-classes (proposed by @kizu and proven to work in WebKit). Maybe it could be useful as a reference?

@kizu

This comment has been minimized.

Show comment
Hide comment
@kizu

kizu Sep 15, 2017

Having something like that :is() instead of the nested :not() hack would be so much better of course.

Though, I'm still thinking about (maybe alongside this :is()) having some way of creating your own cascade level, which you could then place above or below the default author one. This would allow either to import any external library on a level below, or write your styles on a level above, or even write code in multiple levels, like according to @csswizardry's ITCSS.

I understand that that goes beyond the scope of this exact issue, but in my opinion this would cover some of the cases much better and with much less code from the authors (and I think it should be also really easily implementable, the main problem would be in coming up with syntax and handling all the nuances). Below I'd briefly write what I managed to come up with, if that sounds good and there is interest for something like that or at least for discussion, I could create a new issue for it maybe (for [css-cascade] probably?).

  1. By default all the author CSS goes to the default “Normal author” level (or “origin”, but I like the term “layer” for this thing more).

  2. Now, it is possible to create a new “layer”. There are now two possibilities: either this layer would be nameless, or with a set name:

  • Nameless layers: @layer {…} — by default everything that would go into those nameless layers would be put into one layer/origin that is above the one they were declared at. There should be also a way to put those not above, but below the current level, either with some keyword or stuff like @layer (position: below) {…}.
  • Named layers: @layer foo {…} — whenever you declare a new layer this way, it would be placed above the previous declared one (or below if used with a keyword). Then, all the next @layers with the same name would be merged into this place, so the first occurrence matters.
  1. Layers can be nested one into each other, and there should be a way to handle things similar to how we can now handle stacking context & z-index (we should be able both to put the layer somewhere in the global context, or only manage it inside the current layer).

Basically, that's it. There are a lot of nuances and ways to implement some of this stuff, but: the main idea is to have a simple way of separating big chunks of code into independent layers similar to how the cascade of origins works now, basically allowing authors to create multiple author origins (or — split the current author's origin into multiple layers, as all those styles should still be at its place in the cascade).

And, yes, the idea is still raw, and if there is interest we can discuss it in a new issue I guess? And, anyway, I think there regardless should be a way to handle the specificity of selectors like with is(), and I like the proposals for it above.

kizu commented Sep 15, 2017

Having something like that :is() instead of the nested :not() hack would be so much better of course.

Though, I'm still thinking about (maybe alongside this :is()) having some way of creating your own cascade level, which you could then place above or below the default author one. This would allow either to import any external library on a level below, or write your styles on a level above, or even write code in multiple levels, like according to @csswizardry's ITCSS.

I understand that that goes beyond the scope of this exact issue, but in my opinion this would cover some of the cases much better and with much less code from the authors (and I think it should be also really easily implementable, the main problem would be in coming up with syntax and handling all the nuances). Below I'd briefly write what I managed to come up with, if that sounds good and there is interest for something like that or at least for discussion, I could create a new issue for it maybe (for [css-cascade] probably?).

  1. By default all the author CSS goes to the default “Normal author” level (or “origin”, but I like the term “layer” for this thing more).

  2. Now, it is possible to create a new “layer”. There are now two possibilities: either this layer would be nameless, or with a set name:

  • Nameless layers: @layer {…} — by default everything that would go into those nameless layers would be put into one layer/origin that is above the one they were declared at. There should be also a way to put those not above, but below the current level, either with some keyword or stuff like @layer (position: below) {…}.
  • Named layers: @layer foo {…} — whenever you declare a new layer this way, it would be placed above the previous declared one (or below if used with a keyword). Then, all the next @layers with the same name would be merged into this place, so the first occurrence matters.
  1. Layers can be nested one into each other, and there should be a way to handle things similar to how we can now handle stacking context & z-index (we should be able both to put the layer somewhere in the global context, or only manage it inside the current layer).

Basically, that's it. There are a lot of nuances and ways to implement some of this stuff, but: the main idea is to have a simple way of separating big chunks of code into independent layers similar to how the cascade of origins works now, basically allowing authors to create multiple author origins (or — split the current author's origin into multiple layers, as all those styles should still be at its place in the cascade).

And, yes, the idea is still raw, and if there is interest we can discuss it in a new issue I guess? And, anyway, I think there regardless should be a way to handle the specificity of selectors like with is(), and I like the proposals for it above.

@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou

LeaVerou Sep 15, 2017

Contributor

@kizu yeah, @fantasai had a similar idea, you should post about it and link to this issue as well!

Contributor

LeaVerou commented Sep 15, 2017

@kizu yeah, @fantasai had a similar idea, you should post about it and link to this issue as well!

@kizu

This comment has been minimized.

Show comment
Hide comment
@kizu

kizu Sep 15, 2017

Ok, I'll try to find time on this weekend to write up what I have in more details :) And I'm glad to hear someone already had similar ideas! If there are any links to something like that (maybe in csswg mailing lists or elsewhere?), I would be happy to read it.

kizu commented Sep 15, 2017

Ok, I'll try to find time on this weekend to write up what I have in more details :) And I'm glad to hear someone already had similar ideas! If there are any links to something like that (maybe in csswg mailing lists or elsewhere?), I would be happy to read it.

@gregwhitworth

This comment has been minimized.

Show comment
Hide comment
@gregwhitworth

gregwhitworth Sep 19, 2017

Contributor

As @FremyCompany mentioned, I've toyed with a few ideas in this space - primarily enforcing a specificity score at the stylesheet level. That said, there is the potential for more author confusion in this space as you're essentially introducing another layer of specificity (eg: on or off per origin/document/at-rule/stylesheet whatever is decided). The only reason I had opted for stylesheet level (I initially wanted to just opt for off/on for an entire document) is because with components you won't have the same control over whether the components you may be utilizing want/need to cascade and depend on specificity.

I would discourage this one selector being the only selector that nullifies the specificity because that is even more confusing to the additional layer IMO. I think if we do decide this is worth addressing then we should really consider all of the use cases and the way to make this as intuitive to authors as possible.

Contributor

gregwhitworth commented Sep 19, 2017

As @FremyCompany mentioned, I've toyed with a few ideas in this space - primarily enforcing a specificity score at the stylesheet level. That said, there is the potential for more author confusion in this space as you're essentially introducing another layer of specificity (eg: on or off per origin/document/at-rule/stylesheet whatever is decided). The only reason I had opted for stylesheet level (I initially wanted to just opt for off/on for an entire document) is because with components you won't have the same control over whether the components you may be utilizing want/need to cascade and depend on specificity.

I would discourage this one selector being the only selector that nullifies the specificity because that is even more confusing to the additional layer IMO. I think if we do decide this is worth addressing then we should really consider all of the use cases and the way to make this as intuitive to authors as possible.

@inoas

This comment has been minimized.

Show comment
Hide comment
@inoas

inoas Sep 19, 2017

  • 👍 for :is() as a pendent to :not() on the same specificity level - so the authors have the freedom to respect strict specificity
  • 👍 for :filter() like :matches() without specificity - however maybe there can be a more general purpose way to disable/lower specificity of a selector/selector-part?

inoas commented Sep 19, 2017

  • 👍 for :is() as a pendent to :not() on the same specificity level - so the authors have the freedom to respect strict specificity
  • 👍 for :filter() like :matches() without specificity - however maybe there can be a more general purpose way to disable/lower specificity of a selector/selector-part?
@FremyCompany

This comment has been minimized.

Show comment
Hide comment
@FremyCompany

FremyCompany Sep 19, 2017

Contributor

👍 for :is() as a pendent to :not() on the same specificity level - so the authors have the freedom to respect strict specificity

But... isn't that exactly what :matches already does? I would rather have :is or :when be the name of the current :filter proposal. Maybe if you could clarify to me what the difference would be between :not(:not(x)) and :matches(x), then I would reconsider.

Actually, the more I think about it, the more button:when(:hover) really appeals to me. Just look at it: input:when([disabled]). Isn't that wonderful? ^_^

Contributor

FremyCompany commented Sep 19, 2017

👍 for :is() as a pendent to :not() on the same specificity level - so the authors have the freedom to respect strict specificity

But... isn't that exactly what :matches already does? I would rather have :is or :when be the name of the current :filter proposal. Maybe if you could clarify to me what the difference would be between :not(:not(x)) and :matches(x), then I would reconsider.

Actually, the more I think about it, the more button:when(:hover) really appeals to me. Just look at it: input:when([disabled]). Isn't that wonderful? ^_^

@kizu

This comment has been minimized.

Show comment
Hide comment
@kizu

kizu Sep 19, 2017

@FremyCompany The nested :not() with a single selector would be the same as :matches(), but with nested :not() its possible to hack things around for having a specificity of just one class (see http://kizu.ru/en/fun/controlling-the-specificity/#negation-of-negation).

Though, I agree that we can totally have :matches() to be just a shortcut that would keep the specificity, and then we could have the :when() (I like that name too) or something similar that would have no specificity added.

kizu commented Sep 19, 2017

@FremyCompany The nested :not() with a single selector would be the same as :matches(), but with nested :not() its possible to hack things around for having a specificity of just one class (see http://kizu.ru/en/fun/controlling-the-specificity/#negation-of-negation).

Though, I agree that we can totally have :matches() to be just a shortcut that would keep the specificity, and then we could have the :when() (I like that name too) or something similar that would have no specificity added.

@FremyCompany

This comment has been minimized.

Show comment
Hide comment
@FremyCompany

FremyCompany Sep 19, 2017

Contributor

@kizu I see. That's a creative use of :not() ;-)

Contributor

FremyCompany commented Sep 19, 2017

@kizu I see. That's a creative use of :not() ;-)

@dansajin

This comment has been minimized.

Show comment
Hide comment
@dansajin

dansajin Sep 22, 2017

I would prefer something that states very clear what the purpose is. Something like div:nospecifity(:not(#foo):not(#bar):not(#baz)) or even :nospecifity(div:not(#foo):not(#bar):not(#baz)). It will follow the sequence only. Rethinking the latter I am not sure if it makes any sense because everything else has a specifity so it will be always overridden.

dansajin commented Sep 22, 2017

I would prefer something that states very clear what the purpose is. Something like div:nospecifity(:not(#foo):not(#bar):not(#baz)) or even :nospecifity(div:not(#foo):not(#bar):not(#baz)). It will follow the sequence only. Rethinking the latter I am not sure if it makes any sense because everything else has a specifity so it will be always overridden.

@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou

LeaVerou Sep 22, 2017

Contributor

@dansajin I understand the need for explicitness but :nospecificity() is a pain to type and — even worse — a pain to read, especially when used multiple times in the selector.

Contributor

LeaVerou commented Sep 22, 2017

@dansajin I understand the need for explicitness but :nospecificity() is a pain to type and — even worse — a pain to read, especially when used multiple times in the selector.

@gregwhitworth

This comment has been minimized.

Show comment
Hide comment
@gregwhitworth

gregwhitworth Sep 22, 2017

Contributor

@FremyCompany and I spoke about this at length, walked through a few different scenarios and the design of when() or is() is growing on me. With that said, the issue that @dansajin pointed out is a similar annoyance to me. One thing that I noted to @FremyCompany is that you may, say as an author want your entire stylesheet to have 0 specificity so you need to have this selector on every one. We realized that sass solves this problem but that's cumbersome, IMO.

I'm not saying I have the perfect solution here, but what about an at-rule that within any selector gets the same treatment as when() or is(). This allows for not repeating the function - as well as allowing for something like @no-specificity { } or similar to explain what is occurring since when() is essentially combining a filter and nullifying specificity. One downside from this approach (I'm sure people will find others) is that if you only want one selector such as the example above input:when([disabled]) you'd have an additional lines of code due to using an at-rule while when() would be concise.

Contributor

gregwhitworth commented Sep 22, 2017

@FremyCompany and I spoke about this at length, walked through a few different scenarios and the design of when() or is() is growing on me. With that said, the issue that @dansajin pointed out is a similar annoyance to me. One thing that I noted to @FremyCompany is that you may, say as an author want your entire stylesheet to have 0 specificity so you need to have this selector on every one. We realized that sass solves this problem but that's cumbersome, IMO.

I'm not saying I have the perfect solution here, but what about an at-rule that within any selector gets the same treatment as when() or is(). This allows for not repeating the function - as well as allowing for something like @no-specificity { } or similar to explain what is occurring since when() is essentially combining a filter and nullifying specificity. One downside from this approach (I'm sure people will find others) is that if you only want one selector such as the example above input:when([disabled]) you'd have an additional lines of code due to using an at-rule while when() would be concise.

@bkardell

This comment has been minimized.

Show comment
Hide comment
@bkardell

bkardell Sep 22, 2017

I was actually going to suggest that an at-rule might be good here too, but didn't want to get ahead of myself. Pretty nice for custom elements with stuff that exists in the light DOM I think, I've been in a bunch of scenarios where I wanted my default styles to have very low specificity but require attributes or classes to differentiate

bkardell commented Sep 22, 2017

I was actually going to suggest that an at-rule might be good here too, but didn't want to get ahead of myself. Pretty nice for custom elements with stuff that exists in the light DOM I think, I've been in a bunch of scenarios where I wanted my default styles to have very low specificity but require attributes or classes to differentiate

@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou

LeaVerou Sep 23, 2017

Contributor

I think both are useful.
The problem is that nullifying specificity is rarely desirable.
Imagine that every universal selector or type selector from the library user will override anything from the library stylesheet.
The good thing with the pseudo-class is that we can see how authors use it and design the at-rule accordingly, since the at-rule is syntactic sugar for the pseudo-class.

Regarding the name, I like how :when() reads, but I also like the brevity of :is(). I’m fine with either.

Contributor

LeaVerou commented Sep 23, 2017

I think both are useful.
The problem is that nullifying specificity is rarely desirable.
Imagine that every universal selector or type selector from the library user will override anything from the library stylesheet.
The good thing with the pseudo-class is that we can see how authors use it and design the at-rule accordingly, since the at-rule is syntactic sugar for the pseudo-class.

Regarding the name, I like how :when() reads, but I also like the brevity of :is(). I’m fine with either.

@Stolzenhain

This comment has been minimized.

Show comment
Hide comment
@Stolzenhain

Stolzenhain Sep 25, 2017

A new pseudo-class (name TBB, perhaps :filter()?) that works exactly like :matches() but with zero specificity. That way, authors have control over the specificity of their rules, and can choose what is best for their use case.

This is a good proposition because it does what !important is sensibly used for, only in the opposite direction.

Stolzenhain commented Sep 25, 2017

A new pseudo-class (name TBB, perhaps :filter()?) that works exactly like :matches() but with zero specificity. That way, authors have control over the specificity of their rules, and can choose what is best for their use case.

This is a good proposition because it does what !important is sensibly used for, only in the opposite direction.

@ollicle

This comment has been minimized.

Show comment
Hide comment
@ollicle

ollicle Sep 26, 2017

works exactly like :matches() but with zero specificity

This would be magically useful!

Suggest naming this :is

The terseness of :is() gets my vote.

Although, considering:

every selector is an "is" filter already

Presuming there are reasons why :() is not an option?

I guess it would be more difficult to talk about without an explicit name…

ollicle commented Sep 26, 2017

works exactly like :matches() but with zero specificity

This would be magically useful!

Suggest naming this :is

The terseness of :is() gets my vote.

Although, considering:

every selector is an "is" filter already

Presuming there are reasons why :() is not an option?

I guess it would be more difficult to talk about without an explicit name…

@bradkemper

This comment has been minimized.

Show comment
Hide comment
@bradkemper

bradkemper Sep 28, 2017

And if recursion is a problem, we can either limit the number of embedding to some smallish number, or just say that it is limited by memory constraints of implementation.

But the thing I’m getting at, is that you still have useful specificity within each level of the function embedding, which doesn’t affect the specificity of the level above it, except for ties.

bradkemper commented Sep 28, 2017

And if recursion is a problem, we can either limit the number of embedding to some smallish number, or just say that it is limited by memory constraints of implementation.

But the thing I’m getting at, is that you still have useful specificity within each level of the function embedding, which doesn’t affect the specificity of the level above it, except for ties.

@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou

LeaVerou Sep 29, 2017

Contributor

I don't understand why we're going down the heuristic lane again with things like "1/1000th of specificity" when the whole point of this feature is to cancel an unsuccessful heuristic. Typically when you do that, you want to be explicit, not give people another heuristic that could go wrong.
Tab did suggest a second optional parameter for adding specificity, if that is desired, and I agreed (just expressed concern that maybe it should be in the next level).
It seems to me that we are overcomplicating a rather simple feature in the last few comments.

Contributor

LeaVerou commented Sep 29, 2017

I don't understand why we're going down the heuristic lane again with things like "1/1000th of specificity" when the whole point of this feature is to cancel an unsuccessful heuristic. Typically when you do that, you want to be explicit, not give people another heuristic that could go wrong.
Tab did suggest a second optional parameter for adding specificity, if that is desired, and I agreed (just expressed concern that maybe it should be in the next level).
It seems to me that we are overcomplicating a rather simple feature in the last few comments.

@tabatkins

This comment has been minimized.

Show comment
Hide comment
@tabatkins

tabatkins Sep 29, 2017

Member

Agreed. This should start by canceling specificity entirely, so you can add filters to a selector without hecking up your cascade, and possibly also have a specificity control on it. More heuristics and complications defeat the original point entirely.

Member

tabatkins commented Sep 29, 2017

Agreed. This should start by canceling specificity entirely, so you can add filters to a selector without hecking up your cascade, and possibly also have a specificity control on it. More heuristics and complications defeat the original point entirely.

@bradkemper

This comment has been minimized.

Show comment
Hide comment
@bradkemper

bradkemper Sep 29, 2017

Forget about “1/1000 of specificity”, and read my next post. Selectors inside a *:matches() function would always lose to those outside it, just as class selectors always lose to ID selectors. What could go wrong?

I just think that you can have your cake and eat it too, by doing it the way I described. The cascade would be internally very useful still, without hecking up anything outside of the function. We don’t have to throw the baby out with the bath water.

bradkemper commented Sep 29, 2017

Forget about “1/1000 of specificity”, and read my next post. Selectors inside a *:matches() function would always lose to those outside it, just as class selectors always lose to ID selectors. What could go wrong?

I just think that you can have your cake and eat it too, by doing it the way I described. The cascade would be internally very useful still, without hecking up anything outside of the function. We don’t have to throw the baby out with the bath water.

@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou

LeaVerou Sep 29, 2017

Contributor

@bradkemper I’m really not following what exactly is the problem you’re seeing with nested :is(), nor what exactly you’re proposing to fix it.

Contributor

LeaVerou commented Sep 29, 2017

@bradkemper I’m really not following what exactly is the problem you’re seeing with nested :is(), nor what exactly you’re proposing to fix it.

@FremyCompany

This comment has been minimized.

Show comment
Hide comment
@FremyCompany

FremyCompany Sep 30, 2017

Contributor

FWIW, I'm not supportive of this proposal either. I was just pointing out that its technically expensive to do and therefore unlikely to get any implementer traction.

Saying whether or not it has enough use cases is beyond my desire to debate this topic, so I just didn't comment on that (but I tend to agree I do not believe people want this behavior in the uses cases I've seen; in the cases where you want use this, you usually want to use source order and direct control).

EDIT: Just to clarify, these previous comments do not apply to Lea's original idea. That one is easy to implement and both greg and myself have seen clear user cases and demands for such a feature.

Contributor

FremyCompany commented Sep 30, 2017

FWIW, I'm not supportive of this proposal either. I was just pointing out that its technically expensive to do and therefore unlikely to get any implementer traction.

Saying whether or not it has enough use cases is beyond my desire to debate this topic, so I just didn't comment on that (but I tend to agree I do not believe people want this behavior in the uses cases I've seen; in the cases where you want use this, you usually want to use source order and direct control).

EDIT: Just to clarify, these previous comments do not apply to Lea's original idea. That one is easy to implement and both greg and myself have seen clear user cases and demands for such a feature.

@bradkemper

This comment has been minimized.

Show comment
Hide comment
@bradkemper

bradkemper Oct 2, 2017

@LeaVerou,

The problem is not with nested :is(). It is that having zero specificity inside the function just seems too drastic to me. The problem you described is that it it increases the specificity of the whole complex selector to such a degree that it makes it harder to override, or that it itself overrides things you don’t want it to. I think that problem can be overcome by just extending the existing specificity rules, so that the specificity inside the function doesn’t significantly influence selecting, except to break ties in specificity outside the function (just as class selectors don’t matter for specificity except to break ties in ID selectors).

So, the old specificity rules is (roughly) that when there is a tie in ID selectors, you look at class selectors. If that is a tie, you look at type selectors. I would add to that, so that if type selectors are tied, then look at ID selectors inside the :matches(). If that is still a tie, look at class selectors inside the :matches(). If those tie, then look at type selectors inside the :matches(). If those are tied, then look at ID selectors inside the embedded :matches(). And so on.

This allows you to write selectors that are as weak as you like compared to existing selectors, solving your originally stated problems. And inside the functions, you still get the great and important benefits of specificity-based cascading.

This would allow authors to write rules that don’t override things they don’t want to override, and would allow library authors to write rules that were easy for others to override, but without submitting to the tyranny of rule order.

And you could write many rules, with extremely low specificity, without worrying about something like * { max-height: 1000in) (a rule designed to prevent Android from randomly messing up font sizes) from accidentally overriding all the max-height values inside your :is()or matches() functions.

PS for my scheme to work, the :is()or :matches() pseudoclass would also not add its own pseudoclass specificity to the equation. Only the selectors inside it would work as I’ve described.

bradkemper commented Oct 2, 2017

@LeaVerou,

The problem is not with nested :is(). It is that having zero specificity inside the function just seems too drastic to me. The problem you described is that it it increases the specificity of the whole complex selector to such a degree that it makes it harder to override, or that it itself overrides things you don’t want it to. I think that problem can be overcome by just extending the existing specificity rules, so that the specificity inside the function doesn’t significantly influence selecting, except to break ties in specificity outside the function (just as class selectors don’t matter for specificity except to break ties in ID selectors).

So, the old specificity rules is (roughly) that when there is a tie in ID selectors, you look at class selectors. If that is a tie, you look at type selectors. I would add to that, so that if type selectors are tied, then look at ID selectors inside the :matches(). If that is still a tie, look at class selectors inside the :matches(). If those tie, then look at type selectors inside the :matches(). If those are tied, then look at ID selectors inside the embedded :matches(). And so on.

This allows you to write selectors that are as weak as you like compared to existing selectors, solving your originally stated problems. And inside the functions, you still get the great and important benefits of specificity-based cascading.

This would allow authors to write rules that don’t override things they don’t want to override, and would allow library authors to write rules that were easy for others to override, but without submitting to the tyranny of rule order.

And you could write many rules, with extremely low specificity, without worrying about something like * { max-height: 1000in) (a rule designed to prevent Android from randomly messing up font sizes) from accidentally overriding all the max-height values inside your :is()or matches() functions.

PS for my scheme to work, the :is()or :matches() pseudoclass would also not add its own pseudoclass specificity to the equation. Only the selectors inside it would work as I’ve described.

@FremyCompany

This comment has been minimized.

Show comment
Hide comment
@FremyCompany

FremyCompany Oct 2, 2017

Contributor

The problem you described is that it it increases the specificity of the whole complex selector to such a degree that it makes it harder to override

A lot of people just want to use specificity for the core of their matching, but source order for tiny variations on a selector, without having to refactor anything if they change some condition from "a class being present" to "a pair of attributes having certain values" as their apps evolve; your proposal would not help them achieve that.

Contributor

FremyCompany commented Oct 2, 2017

The problem you described is that it it increases the specificity of the whole complex selector to such a degree that it makes it harder to override

A lot of people just want to use specificity for the core of their matching, but source order for tiny variations on a selector, without having to refactor anything if they change some condition from "a class being present" to "a pair of attributes having certain values" as their apps evolve; your proposal would not help them achieve that.

@FremyCompany

This comment has been minimized.

Show comment
Hide comment
@FremyCompany

FremyCompany Oct 2, 2017

Contributor

From what I understand of the current state of css usage, with websites moving towards component-splitting of their files instead of type-splitting for their files, stylesheets files used in development have grown smaller and smaller, and targetted to specific portions of the application; using source order makes more sense than using the specificity cascade at that scale.

You still want specificity rules for more generic theming purposes, and to allow the style of one component to override its sub component' styles if needed, but "local state" of a component is something people don't want to have an impact on specificity, hence this proposal generating zero specificity.

It doesn't require major changes to how browsers do cascade unlike your proposal, and solves the currently most dire issue. I haven't heard anyone desiring your proposed behavior before. I don't want to say it doesn't have value, but it doesn't seem like an appropriate design to solve the most frequently-heard-about problem.

Contributor

FremyCompany commented Oct 2, 2017

From what I understand of the current state of css usage, with websites moving towards component-splitting of their files instead of type-splitting for their files, stylesheets files used in development have grown smaller and smaller, and targetted to specific portions of the application; using source order makes more sense than using the specificity cascade at that scale.

You still want specificity rules for more generic theming purposes, and to allow the style of one component to override its sub component' styles if needed, but "local state" of a component is something people don't want to have an impact on specificity, hence this proposal generating zero specificity.

It doesn't require major changes to how browsers do cascade unlike your proposal, and solves the currently most dire issue. I haven't heard anyone desiring your proposed behavior before. I don't want to say it doesn't have value, but it doesn't seem like an appropriate design to solve the most frequently-heard-about problem.

@kizu

This comment has been minimized.

Show comment
Hide comment
@kizu

kizu Oct 2, 2017

The second best thing about the zero-specificity matching (after its zero specificity itself) would be that it would work in the most straightforward and easily understandable (after you'll once get what it is doing) way. You won't need to do any calculations, as zero is the easiest stuff to operate. Having something inbetween would introduce an extra cognitive load: you'll suddenly need to look at the selectors in order to understand which exact specificity they have. And if selector would have multiple instances of this semi-specificity stuff?

I already can see how the zero-specificity stuff would be useful (and maybe when we'd have them we wouldn't even need that much the proposal that I described above?) for the stuff I do in CSS, and I need it yesterday. While just thinking about how to manage the sublevels of specificity makes me a bit dizzy.

kizu commented Oct 2, 2017

The second best thing about the zero-specificity matching (after its zero specificity itself) would be that it would work in the most straightforward and easily understandable (after you'll once get what it is doing) way. You won't need to do any calculations, as zero is the easiest stuff to operate. Having something inbetween would introduce an extra cognitive load: you'll suddenly need to look at the selectors in order to understand which exact specificity they have. And if selector would have multiple instances of this semi-specificity stuff?

I already can see how the zero-specificity stuff would be useful (and maybe when we'd have them we wouldn't even need that much the proposal that I described above?) for the stuff I do in CSS, and I need it yesterday. While just thinking about how to manage the sublevels of specificity makes me a bit dizzy.

@LeaVerou

This comment has been minimized.

Show comment
Hide comment
@LeaVerou

LeaVerou Oct 2, 2017

Contributor

Exactly what @kizu and @FremyCompany said. This kind of thing is needed yesterday, so complicating it further really doesn't help. If some specificity is desired, one can always make it so by using :is() for only a part of their selector (which I assume is how most people will use it, putting only the filters in :is()).

Contributor

LeaVerou commented Oct 2, 2017

Exactly what @kizu and @FremyCompany said. This kind of thing is needed yesterday, so complicating it further really doesn't help. If some specificity is desired, one can always make it so by using :is() for only a part of their selector (which I assume is how most people will use it, putting only the filters in :is()).

@inoas

This comment has been minimized.

Show comment
Hide comment
@inoas

inoas Oct 3, 2017

but without submitting to the tyranny of rule order.

I want to emphasis this note above^. I'd rather deal with specificity than file/rule loading order.

E.g.: :matches() should really NOT be changed but :filter() could be added to behave like matches but without adding any specificity. This gives authors freedom to respect to prefer the struggle with file load/rule order or specificity.

:matches() should also not be changed because it is out there in the wild already potentially breaking existing applications.


From what I understand of the current state of css usage, with websites moving towards component-splitting of their files instead of type-splitting for their files, stylesheets files used in development have grown smaller and smaller, and targetted to specific portions of the application; using source order makes more sense than using the specificity cascade at that scale.
You still want specificity rules for more generic theming purposes, and to allow the style of one component to override its sub component' styles if needed, but "local state" of a component is something people don't want to have an impact on specificity, hence this proposal generating zero specificity.

... and ...

While just thinking about how to manage the sublevels of specificity makes me a bit dizzy.

Again: Would declarative-shadow DOMs help because they could reset styles and work around specificity issues on a component based level?

inoas commented Oct 3, 2017

but without submitting to the tyranny of rule order.

I want to emphasis this note above^. I'd rather deal with specificity than file/rule loading order.

E.g.: :matches() should really NOT be changed but :filter() could be added to behave like matches but without adding any specificity. This gives authors freedom to respect to prefer the struggle with file load/rule order or specificity.

:matches() should also not be changed because it is out there in the wild already potentially breaking existing applications.


From what I understand of the current state of css usage, with websites moving towards component-splitting of their files instead of type-splitting for their files, stylesheets files used in development have grown smaller and smaller, and targetted to specific portions of the application; using source order makes more sense than using the specificity cascade at that scale.
You still want specificity rules for more generic theming purposes, and to allow the style of one component to override its sub component' styles if needed, but "local state" of a component is something people don't want to have an impact on specificity, hence this proposal generating zero specificity.

... and ...

While just thinking about how to manage the sublevels of specificity makes me a bit dizzy.

Again: Would declarative-shadow DOMs help because they could reset styles and work around specificity issues on a component based level?

@kizu

This comment has been minimized.

Show comment
Hide comment
@kizu

kizu Oct 3, 2017

Again: Would declarative-shadow DOMs help because they could reset styles and work around specificity issues on a component based level?

For my use cases — no. I've already mentioned ITCSS — I'm using something similar to this, and saw other people using something similar to this. For our cases, having a better control over specificity means:

  1. We would be able to create a better “default” styles (example: normalize.css — it has selectors like abbr[title], which are harder to override from your styles) easier and without a fear that adding new styles would mean we'd need to override stuff (we could have complicated rules for basic typography of elements like h1 + p, li > p:first-child etc. but with a specificity of one element, thus easily overridable).

  2. We could make it sure the modifiers (in BEM notation) for our elements would always override the default styles, even if we'd need to have those default styles complex enough (like having a .input class which has different styles for textarea.input & input.input, but in a way later introduced .input--bright would override both of those more complex selectors).

  3. With build tools like PostCSS or anything similar we could make it so that different levels of ITCSS wouldn't override each other (and those different levels can surely be used together on the same elements). Right now it is possible only by adding an excessive amount of extra classes/[class] to selectors, which is clearly a hack.

All of those cases (and there are more of them) don't have anything shadow DOM would help with.

kizu commented Oct 3, 2017

Again: Would declarative-shadow DOMs help because they could reset styles and work around specificity issues on a component based level?

For my use cases — no. I've already mentioned ITCSS — I'm using something similar to this, and saw other people using something similar to this. For our cases, having a better control over specificity means:

  1. We would be able to create a better “default” styles (example: normalize.css — it has selectors like abbr[title], which are harder to override from your styles) easier and without a fear that adding new styles would mean we'd need to override stuff (we could have complicated rules for basic typography of elements like h1 + p, li > p:first-child etc. but with a specificity of one element, thus easily overridable).

  2. We could make it sure the modifiers (in BEM notation) for our elements would always override the default styles, even if we'd need to have those default styles complex enough (like having a .input class which has different styles for textarea.input & input.input, but in a way later introduced .input--bright would override both of those more complex selectors).

  3. With build tools like PostCSS or anything similar we could make it so that different levels of ITCSS wouldn't override each other (and those different levels can surely be used together on the same elements). Right now it is possible only by adding an excessive amount of extra classes/[class] to selectors, which is clearly a hack.

All of those cases (and there are more of them) don't have anything shadow DOM would help with.

@inoas

This comment has been minimized.

Show comment
Hide comment
@inoas

inoas Oct 3, 2017

As for default styles, having a way to disable or lower specificity would really be great 👍 That covers your 1. and 2. IMHO (I am a user/contributor of Marx.css which is IMHO an opinionated normalize.css and having lower specificity will help doing what Marx/normalize do a lot easier).

However do you agree that :matches should not be overwritten to allow authors to work with specificity rather than having to depend on 3rd party tool-stacks (like PostCSS et al.)? Wouldn't a new :filter() fit your bill?

inoas commented Oct 3, 2017

As for default styles, having a way to disable or lower specificity would really be great 👍 That covers your 1. and 2. IMHO (I am a user/contributor of Marx.css which is IMHO an opinionated normalize.css and having lower specificity will help doing what Marx/normalize do a lot easier).

However do you agree that :matches should not be overwritten to allow authors to work with specificity rather than having to depend on 3rd party tool-stacks (like PostCSS et al.)? Wouldn't a new :filter() fit your bill?

@kizu

This comment has been minimized.

Show comment
Hide comment
@kizu

kizu Oct 3, 2017

I'm more for :matches() for having its specificity in a place, and for :is() for having zero specificity. Having a zero-specificity complex selectors would surely make it so it would be possible to write complex stuff without relying on third-party tools, though they could still be helpful even in that case by making some things easier.

kizu commented Oct 3, 2017

I'm more for :matches() for having its specificity in a place, and for :is() for having zero specificity. Having a zero-specificity complex selectors would surely make it so it would be possible to write complex stuff without relying on third-party tools, though they could still be helpful even in that case by making some things easier.

@mattbrundage

This comment has been minimized.

Show comment
Hide comment
@mattbrundage

mattbrundage Oct 13, 2017

This is a good proposition because it does what !important is sensibly used for, only in the opposite direction.

@Stolzenhain , For the longest time, I've half-jokingly suggested to my coworkers that we need a complementary !unimportant keyword that we could apply to a selector. It's good to see that this basic concept is getting some traction.

mattbrundage commented Oct 13, 2017

This is a good proposition because it does what !important is sensibly used for, only in the opposite direction.

@Stolzenhain , For the longest time, I've half-jokingly suggested to my coworkers that we need a complementary !unimportant keyword that we could apply to a selector. It's good to see that this basic concept is getting some traction.

@bradkemper

This comment has been minimized.

Show comment
Hide comment
@bradkemper

bradkemper Oct 28, 2017

Something like this would be nice:

@specificity lower {
    @specificity lower {
         ...
         @specificity none {
                 ...
          }
     }
}

bradkemper commented Oct 28, 2017

Something like this would be nice:

@specificity lower {
    @specificity lower {
         ...
         @specificity none {
                 ...
          }
     }
}

@astearns astearns removed the Agenda+ F2F label Nov 6, 2017

@css-meeting-bot

This comment has been minimized.

Show comment
Hide comment
@css-meeting-bot

css-meeting-bot Nov 7, 2017

Member

The Working Group just discussed Functional pseudo-class like :matches() with 0 specificity, and agreed to the following resolutions:

  • RESOLVED: Add to selectors level 4 with a TBD name.
The full IRC log of that discussion <leaverou> topic: Functional pseudo-class like :matches() with 0 specificity
<eae> leaverou: As we all know specificity tries to infer importance from selectors. Resulting specificity might not always be logical.
<astearns> github: https://github.com/w3c/csswg-drafts/issues/1170
<Chris_> github, delete all comments
<eae> leaverou: My favorite example of specificity not being a good heuristic is using the not pseudo class.
<leaverou> div:not(#foo):not(#bar):not(#baz)
<eae> leaverou: ^^^
<eae> leaverou: In this example we want to target all dives except three, yet gets very high specificity.
<eae> leaverou: Especially for libraries, when trying to be specific, it is hard to override.
<eae> leaverou: uses something called BAM(?) encodes selector in class name and uses js to apply it.
<bradk_> BEM
<TabAtkins> s/BAM/BEM/
<Chris_> .how__many__people__have__hear__of__bem
<eae> leaverou: Willing to not use selectors at all, to bypass specificity.
<bradk_> http://getbem.com/introduction/
<eae> leaverou: One way to fix this would be to define selectors with a known specificity of one, would allow last selector win and make it easier to override.
<fantasai> q+
<eae> leaverou: I.e. put all nots in a single pseduo class. Easy solution vs other ones like per origin.
<eae> leaverou: Lets one be very specific with regardess to specificty, can be selected per selector and solves most of the known problems.
<eae> leaverou: Something that could be done as a pre-processor.
<eae> leaverou: Many names have been proposed, we can bikeshed that.
<eae> fantasai: Seems like a reasonable idea to me. The fact that authors can chose which parts of the selector applies to specificity sounds good to me.
<bkardell_> ?+
<eae> fantasai: Lower priority for an entire style sheet, library author might want to allow the entire stylesheet to be allowed to be overriden by author rules.
<Rossen> q?
<eae> leaverou: Example: in ?? there is a toolbar that has a class of mv-bar, also class of mv-ui that means applpy default style. Want author to be able to overrule using just mv-bar but I don't want their "div" rules to override.
<bradk_> q+
<astearns> s/??/mavo/
<Rossen> ack fantasai
<Rossen> ack bkardell_
<eae> bkardell_: I don't think they are mutually exclusive. May be that you can do an awful lot for a whole bunch of things and we know we can do that easily.
<eae> bkardell_: For a number of polyfills that I have worked on this would have been really useful.
<eae> bkardell_: There are things like headings that need to take aria roles into account that make them have very high specificity which makes it hard to override.
<TabAtkins> q+
<Rossen> ack bradk_
<eae> bradk_: Seems to me like we could solve this without taking specificity all the way down to zero.
<eae> bradk_: Specificty only matters when there is a tie.
<eae> bradk_: If there is a tie when it comes to ID or class, if the ID selector inside the funciton was more specific then outside the function that would solve the same problem while still allowoing specificity.
<Rossen> q?
<fantasai> Dael, here's the diagrams for Nat's presentation on line grids; please insert them in the correct section of the minutes. :) https://lists.w3.org/Archives/Public/www-archive/2017Nov/att-0008/CSSWG_2017.11.6_nmccully.pdf
<eae> leaverou: As dicussed in issue, if we have fractions of specificity that introduces new levels of specificity and no one is suggestion that the entire thing doesn't have specicifity. All the classes and IDs outside of it still applies. It allows the specificity to be controlled. To have it count as a class you would just add it to the end, a bit hacky.
<eae> bradk_: No use case for specifying it for the entire selector?
<eae> leaverou: Yes but usaully not. You would only want to [put some criteria in the pseduo class. Like all the not for example.
<eae> leaverou: Makes it less predictable. Now we know that we can count the number of IDs, number of classes, tags etc. If it is always zero it is very obiovus, if not it makes it much more complciated to compute it.
<Rossen> q?
<Rossen> ack TabAtkins
<eae> TabAtkins: I agree in general with what leaverou is saying. Authors can often do just fine when specificity is in order. Opting out or in-order seems ot match what users want.
<eae> TabAtkins: AS for chrome, we're happy with this, and would like to implement the stornger version of matches. This is easier, we might do this firts.
<eae> TabAtkins: We're supportive.
<Rossen> q?
<eae> florian: Let's put this in level 4 for now, we don't have a five.
<eae> fantasai:
<eae> Rossen: Let's add it to four.
<eae> fantasai: Very simple feature, as long as we're happy with the name.
<eae> ericwillgers: What about web platform tests?
<eae> fantasai: Not in CR yet, not needed.
<eae> <laughter>
<dbaron> q+
<eae> dbaron: One comment: I think it is worth nothing that it is not clear how easy it would be to implement matches. This has most of the same risk.
<Rossen> ack dbaron
<eae> dbaron: One of the things with selectors, they're heavily optimized. Implementing without optimizaions not very useful. With optimizations is quite a bit of work and not clear how quickly that can happen.
<eae> fantasai: Start with implemented subset.
<eae> TabAtkins: WebKit goes beyond spec, also has support for pseduo elements.
<eae> dbaron: Caution in that it's being tied to a feature which has an uncertain future.
<eae> fantasai: De-risk by having certain things in level 4 vs 5.
<eae> dbaron: Other alternatives that solves leaverou use cases.
<eae> leaverou: I don't want to reduce *all* of it to zero but only a part.
<bkardell_> ?+
<Chris_> q?
<eae> dbaron: I don't have a syntax proposal at this time but would avoid tie to branching combinators.
<eae> TabAtkins: Earliest version didn't support that, does not.
<eae> does now.
<bkardell_> ?-
<eae> fantasai: Making up a completely new unrelated syntax seems silly and doesn't make sense. Cut down on the syntax instead.
<Rossen> q?
<eae> dbaron: What doesn't make sense to me is spec moving so far ahead of what implementors are willing to do. Implementor by-in was not a factor.
<eae> fantasai: Disagree, you're arguing against it based on implementation priority.
<Chris_> s/by-in/buy-in
<eae> dbaron: you're acting like we can only do everything or nothing.
<fantasai> eae, that's not what I said
<eae> fantasai: Not what I said.
<fantasai> at all
<eae> dbaron: I'm fine with the proposal but I do not think it's the only one.
<eae> leaverou: If implementors aren't willing to do that at the moement shouldn't we discuss that?
<eae> dbaron: I think I bought this up when we went to CR
<eae> fantasai: Selectors are not in CR yet.
<eae> dbaron: But people are goimg ahead to implement it.
<leaverou> s/aren't willing to do that/aren't willing to implement a part of :matches()/
<eae> dbaron: This is the problem with sticking things in editors draft.
<fantasai> There shouldn't be anything in Selectors that didn't have a WG resolution to add.
<eae> Rossen: Would you prefer to see this go in in another way? If not can we try to settle on a resoluiton and go on.
<fantasai> If there is, the editors made a mistake.
<fantasai> If there was a resolution and you didn't like it you should have objected.
<eae> dbaron: Fine with matches without combinators under a different name.
<fantasai> Being angry about it now is neither helpful nor fair.
<bkardell_> q+
<eae> leaverou: I'm fine with that (adding combinators later)
<eae> TabAtkins: The no combinators version is the one that desugars effecitvely. Start with simple version.
<eae> leaverou: Still supports commas, right?
<Rossen> q?
<eae> TabAtkins: Yes
<eae> bkardell_: Is there a suggestion to take combinators out of matches level 4 as well?
<eae> TabAtkins: Yes
<eae> Rossen: Are you OK with that?
<eae> leaverou: Yes, can we have a resolution?
<dbaron> fwiw, we did discuss moving selectors4 to cr at least in https://lists.w3.org/Archives/Public/www-style/2015Jul/0349.html
<eae> Proposed resolution: Add to selectors level 4 with a TBD name
<eae> RESOLVED: Add to selectors level 4 with a TBD name.
<eae> fantasai: Do we have a list of candidate names?
<eae> leaverou: is, when, and filter
<eae> Rossen: Any particular favorite we can resolve on right now?
<eae> ericwilingers: I like filter
<eae> Rossen: filter has the most plusses on github?
<eae> leaverou: No, I think it was either is or when.
<dbaron> filter is also the name of a property
<eae> Rossen: You all work it out.
<eae> Rossen: let's move on.
Member

css-meeting-bot commented Nov 7, 2017

The Working Group just discussed Functional pseudo-class like :matches() with 0 specificity, and agreed to the following resolutions:

  • RESOLVED: Add to selectors level 4 with a TBD name.
The full IRC log of that discussion <leaverou> topic: Functional pseudo-class like :matches() with 0 specificity
<eae> leaverou: As we all know specificity tries to infer importance from selectors. Resulting specificity might not always be logical.
<astearns> github: https://github.com/w3c/csswg-drafts/issues/1170
<Chris_> github, delete all comments
<eae> leaverou: My favorite example of specificity not being a good heuristic is using the not pseudo class.
<leaverou> div:not(#foo):not(#bar):not(#baz)
<eae> leaverou: ^^^
<eae> leaverou: In this example we want to target all dives except three, yet gets very high specificity.
<eae> leaverou: Especially for libraries, when trying to be specific, it is hard to override.
<eae> leaverou: uses something called BAM(?) encodes selector in class name and uses js to apply it.
<bradk_> BEM
<TabAtkins> s/BAM/BEM/
<Chris_> .how__many__people__have__hear__of__bem
<eae> leaverou: Willing to not use selectors at all, to bypass specificity.
<bradk_> http://getbem.com/introduction/
<eae> leaverou: One way to fix this would be to define selectors with a known specificity of one, would allow last selector win and make it easier to override.
<fantasai> q+
<eae> leaverou: I.e. put all nots in a single pseduo class. Easy solution vs other ones like per origin.
<eae> leaverou: Lets one be very specific with regardess to specificty, can be selected per selector and solves most of the known problems.
<eae> leaverou: Something that could be done as a pre-processor.
<eae> leaverou: Many names have been proposed, we can bikeshed that.
<eae> fantasai: Seems like a reasonable idea to me. The fact that authors can chose which parts of the selector applies to specificity sounds good to me.
<bkardell_> ?+
<eae> fantasai: Lower priority for an entire style sheet, library author might want to allow the entire stylesheet to be allowed to be overriden by author rules.
<Rossen> q?
<eae> leaverou: Example: in ?? there is a toolbar that has a class of mv-bar, also class of mv-ui that means applpy default style. Want author to be able to overrule using just mv-bar but I don't want their "div" rules to override.
<bradk_> q+
<astearns> s/??/mavo/
<Rossen> ack fantasai
<Rossen> ack bkardell_
<eae> bkardell_: I don't think they are mutually exclusive. May be that you can do an awful lot for a whole bunch of things and we know we can do that easily.
<eae> bkardell_: For a number of polyfills that I have worked on this would have been really useful.
<eae> bkardell_: There are things like headings that need to take aria roles into account that make them have very high specificity which makes it hard to override.
<TabAtkins> q+
<Rossen> ack bradk_
<eae> bradk_: Seems to me like we could solve this without taking specificity all the way down to zero.
<eae> bradk_: Specificty only matters when there is a tie.
<eae> bradk_: If there is a tie when it comes to ID or class, if the ID selector inside the funciton was more specific then outside the function that would solve the same problem while still allowoing specificity.
<Rossen> q?
<fantasai> Dael, here's the diagrams for Nat's presentation on line grids; please insert them in the correct section of the minutes. :) https://lists.w3.org/Archives/Public/www-archive/2017Nov/att-0008/CSSWG_2017.11.6_nmccully.pdf
<eae> leaverou: As dicussed in issue, if we have fractions of specificity that introduces new levels of specificity and no one is suggestion that the entire thing doesn't have specicifity. All the classes and IDs outside of it still applies. It allows the specificity to be controlled. To have it count as a class you would just add it to the end, a bit hacky.
<eae> bradk_: No use case for specifying it for the entire selector?
<eae> leaverou: Yes but usaully not. You would only want to [put some criteria in the pseduo class. Like all the not for example.
<eae> leaverou: Makes it less predictable. Now we know that we can count the number of IDs, number of classes, tags etc. If it is always zero it is very obiovus, if not it makes it much more complciated to compute it.
<Rossen> q?
<Rossen> ack TabAtkins
<eae> TabAtkins: I agree in general with what leaverou is saying. Authors can often do just fine when specificity is in order. Opting out or in-order seems ot match what users want.
<eae> TabAtkins: AS for chrome, we're happy with this, and would like to implement the stornger version of matches. This is easier, we might do this firts.
<eae> TabAtkins: We're supportive.
<Rossen> q?
<eae> florian: Let's put this in level 4 for now, we don't have a five.
<eae> fantasai:
<eae> Rossen: Let's add it to four.
<eae> fantasai: Very simple feature, as long as we're happy with the name.
<eae> ericwillgers: What about web platform tests?
<eae> fantasai: Not in CR yet, not needed.
<eae> <laughter>
<dbaron> q+
<eae> dbaron: One comment: I think it is worth nothing that it is not clear how easy it would be to implement matches. This has most of the same risk.
<Rossen> ack dbaron
<eae> dbaron: One of the things with selectors, they're heavily optimized. Implementing without optimizaions not very useful. With optimizations is quite a bit of work and not clear how quickly that can happen.
<eae> fantasai: Start with implemented subset.
<eae> TabAtkins: WebKit goes beyond spec, also has support for pseduo elements.
<eae> dbaron: Caution in that it's being tied to a feature which has an uncertain future.
<eae> fantasai: De-risk by having certain things in level 4 vs 5.
<eae> dbaron: Other alternatives that solves leaverou use cases.
<eae> leaverou: I don't want to reduce *all* of it to zero but only a part.
<bkardell_> ?+
<Chris_> q?
<eae> dbaron: I don't have a syntax proposal at this time but would avoid tie to branching combinators.
<eae> TabAtkins: Earliest version didn't support that, does not.
<eae> does now.
<bkardell_> ?-
<eae> fantasai: Making up a completely new unrelated syntax seems silly and doesn't make sense. Cut down on the syntax instead.
<Rossen> q?
<eae> dbaron: What doesn't make sense to me is spec moving so far ahead of what implementors are willing to do. Implementor by-in was not a factor.
<eae> fantasai: Disagree, you're arguing against it based on implementation priority.
<Chris_> s/by-in/buy-in
<eae> dbaron: you're acting like we can only do everything or nothing.
<fantasai> eae, that's not what I said
<eae> fantasai: Not what I said.
<fantasai> at all
<eae> dbaron: I'm fine with the proposal but I do not think it's the only one.
<eae> leaverou: If implementors aren't willing to do that at the moement shouldn't we discuss that?
<eae> dbaron: I think I bought this up when we went to CR
<eae> fantasai: Selectors are not in CR yet.
<eae> dbaron: But people are goimg ahead to implement it.
<leaverou> s/aren't willing to do that/aren't willing to implement a part of :matches()/
<eae> dbaron: This is the problem with sticking things in editors draft.
<fantasai> There shouldn't be anything in Selectors that didn't have a WG resolution to add.
<eae> Rossen: Would you prefer to see this go in in another way? If not can we try to settle on a resoluiton and go on.
<fantasai> If there is, the editors made a mistake.
<fantasai> If there was a resolution and you didn't like it you should have objected.
<eae> dbaron: Fine with matches without combinators under a different name.
<fantasai> Being angry about it now is neither helpful nor fair.
<bkardell_> q+
<eae> leaverou: I'm fine with that (adding combinators later)
<eae> TabAtkins: The no combinators version is the one that desugars effecitvely. Start with simple version.
<eae> leaverou: Still supports commas, right?
<Rossen> q?
<eae> TabAtkins: Yes
<eae> bkardell_: Is there a suggestion to take combinators out of matches level 4 as well?
<eae> TabAtkins: Yes
<eae> Rossen: Are you OK with that?
<eae> leaverou: Yes, can we have a resolution?
<dbaron> fwiw, we did discuss moving selectors4 to cr at least in https://lists.w3.org/Archives/Public/www-style/2015Jul/0349.html
<eae> Proposed resolution: Add to selectors level 4 with a TBD name
<eae> RESOLVED: Add to selectors level 4 with a TBD name.
<eae> fantasai: Do we have a list of candidate names?
<eae> leaverou: is, when, and filter
<eae> Rossen: Any particular favorite we can resolve on right now?
<eae> ericwilingers: I like filter
<eae> Rossen: filter has the most plusses on github?
<eae> leaverou: No, I think it was either is or when.
<dbaron> filter is also the name of a property
<eae> Rossen: You all work it out.
<eae> Rossen: let's move on.
@dbaron

This comment has been minimized.

Show comment
Hide comment
@dbaron

dbaron Nov 8, 2017

Member

For what it's worth (responding to my own comments in the minutes above), I might be wrong about which aspects of :matches() are hard -- maybe the branching doesn't add that much complexity -- and difficulty with specificity wouldn't be present here, although there may still be issues with implementing the various class/tag/id and bloom filter optimizations to make :matches() equivalent in performance to the old way of saying the same thing. It does appear I had the opposite opinion before (about how bad the branching of combinators resulting from allowing combinators inside :matches() was). But I think it's still a relatively complex feature, and that tying the ability to drop specificity to :matches() does hurt the chances of getting the ability to drop specificity sooner.

Member

dbaron commented Nov 8, 2017

For what it's worth (responding to my own comments in the minutes above), I might be wrong about which aspects of :matches() are hard -- maybe the branching doesn't add that much complexity -- and difficulty with specificity wouldn't be present here, although there may still be issues with implementing the various class/tag/id and bloom filter optimizations to make :matches() equivalent in performance to the old way of saying the same thing. It does appear I had the opposite opinion before (about how bad the branching of combinators resulting from allowing combinators inside :matches() was). But I think it's still a relatively complex feature, and that tying the ability to drop specificity to :matches() does hurt the chances of getting the ability to drop specificity sooner.

@o-t-w

This comment has been minimized.

Show comment
Hide comment
@o-t-w

o-t-w Nov 28, 2017

:is is the perfect name. Keep it simple and implement as soon as possible 🎉

The issue raised at the end of the IRC discussion is important. Having a property and a selector named the same thing isn't ideal so I think filter would be a bad choice.

o-t-w commented Nov 28, 2017

:is is the perfect name. Keep it simple and implement as soon as possible 🎉

The issue raised at the end of the IRC discussion is important. Having a property and a selector named the same thing isn't ideal so I think filter would be a bad choice.

@LeaVerou LeaVerou added the Needs Edits label Dec 1, 2017

@LeaVerou LeaVerou closed this in 5948b1c Dec 1, 2017

triple-underscore added a commit to triple-underscore/triple-underscore.github.io that referenced this issue Dec 3, 2017

[selectors-4] Add :is() 他
Add :target-within to Changes section
w3c/csswg-drafts@0fdb0f8
35013a1a000

Add :target-within, resolves
w3c/csswg-drafts#457
w3c/csswg-drafts@d517bca
059c948402e

Add :focus-within to Overview
w3c/csswg-drafts@0933c54
66f1e561780

Add :is() example in specificity section, and add it in…
w3c/csswg-drafts@a9fddaf
ccc35486939

Add :is(), resolves w3c/csswg-drafts#1170
w3c/csswg-drafts@5948b1c
9dd2c233329

Remove issue about :any-link naming, now that it's widely implemented.
w3c/csswg-drafts@33ae097
632b1b1eaf3

fantasai added a commit that referenced this issue Dec 28, 2017

@fantasai

This comment has been minimized.

Show comment
Hide comment
@fantasai

fantasai Dec 28, 2017

Contributor

I filed #2143 for further discussion on the name, as we haven't decided on it.

I also marked this as an open issue in the draft and named the pseudo-class :something() for now so that it's really obvious that it needs a name.

Contributor

fantasai commented Dec 28, 2017

I filed #2143 for further discussion on the name, as we haven't decided on it.

I also marked this as an open issue in the draft and named the pseudo-class :something() for now so that it's really obvious that it needs a name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment