allow way to lift selector specificity
futurist opened this issue · 22 comments
when has something set in b.css
using class as selector, it's very easy to override inline bss definitions.
Please see this demo
The li
never be blue
.
Is there any way to lift selector specificity?
That's a good point, although I think adding class specific styling like (ul.wrap li
) using b.css
kind of defeats the purpose of bss..
Techically bss could repeat the class twice to get higher priority.
To be honest I almost like that the example won't work since it exposes a potential dangerous global css class styling.
Would love to hear your use case for this?
The use case is easy to find, even in flems, like below line:
https://github.com/porsager/flems/blob/efa332291686d5e541a873d667ed158e961b10d5/src/styles.js#L16
You cannot set inline link color anymore!
I'm sorry, you are so right
That right there has actually already resulted in a bug in flems
I'll try to think about a better solution wrt. specificity than the above one.. Ideas are more than welcome..
Repeat the class is the resonable way, for performance, I think below is good for a test:
https://benfrain.com/css-performance-revisited-selectors-bloat-expensive-styles/
I made a test result of repeat class selector using above repo, please see attached results.
Conclusion: repeat 100 class selector version seems have no observable performance reduction.
Thanks @futurist.
This change will also solve the same issue for styles set with $nest if i make sure to not add the class twice when using nest!
I've got a fix almost ready.
Thanks a lot!
I've always used the following selector fragment to increase specificity:
:nth-child(n)
It's semantically null and always valid. Despite it looking hacky (everything is hacky for this feature – there is no semantically correct 'but more specific'), I feel it's a better indicator when reading the generated code: it's clearly done by intent, and with an understanding of the mechanic there's clearly nothing else it could be doing.
Ah, that's clever Barney! Hadn't seen that before, but now that we're improving, I think I like :root .className
better.
I am still thinking about wether this will be a good idea to solve generally instead of having to solve it by adding an explicit specificity bumper method.
By that I mean always generate sheet selectors as :root .className
unless it's applied using $nest
. I think that would take care of most use cases, and of course we could also add a method to increase the number of :root:root:root
added manually to bump specificity?
What do you think about that solution @futurist and @barneycarroll
I think :root
is better, +1 for this
Thanks @futurist
@barneycarroll do you see any downsides to doing the :root
thing generally?
Hey @barneycarroll .
I'd still love your input on the above (although this issue is closed), and before i release this change
It looks nicer, but it won't work if the targeted element is the root. Given that BSS-generated selectors don't have any human readable semantics I think the comprehensive solution is better.
That's a good point Barney!
I just did some testing, and it seems neither :root
nor :nth-child(n)
can be used with the root (eg html
). Only double class name seems to work. Am I doing something wrong, or are we back at doing the double class name solution ?
classes and pseudos both have a selector specificity order of 2 (tagnames being 1, ids being 3, inline style being 4). Volume of any given one of those categories can trump another in the same order, but any of a higher order will trump them. Outside of that, order of declaration trumps all.
In your example @porsager you have 3 rules with competing property declarations, and all of them have selectors consisting of exactly 2 2nd-order selector components. Therefore, the last one will win out: pseudos don't trump classes, they're equivalent.
In order to increase specificity, we need a generic selector of that same 2nd order of power which can trump potentially later-defined classes by a step of 1. The example doesn't show that specificity increase.
The point I'm making is that if we increase that specificity by appending an extra semantically null entity, we have a procedural mechanism for increasing specificity that can be applied in any situation. And that can't be done by prepending :root
because :root html
is semantically invalid.
When all's said and done, the class duplication mechanism is probably better… I think
Ah, I see what's going on :P Try my or your example in safari ;) .test:nth-child(n)
will never be applied on <html>
.
It works in chrome though, which I didn't find out until I guessed that's why you saw it as working.
I know about the specificity, but I think browser incompatibilities just got the better of us ;) (obviously a safari bug in the case of :nth-child(n)
not working).
LOL, of course. How condescending of me, to think that I could treat the primordial ancestor as a child! Classname duplication and concatenation best option then?
I'd like to use :nth-child(n)
since your argument for it makes very much sense to me, but since I don't want to wait for safari fixes (haven't tested other browsers), I guess class name duplication is the way to go..
Haha
Eh, actually I think that makes sense. The root element is not a child.
I noticed it's only repeat 2 times. How to add more repeation?
@futurist Yeah, that was to solve the most prevalent cases, and I'm leaning towards suggesting $nest(':nth-child(n), ...)'
for adding specificity instead of making a dedicated method for it (eg. something like b.$priority(n) | b.$classRepeat(n)
).
I'd love to hear your opinion and @barneycarroll 's as well, but my thinking is that if you're in a specificity war, it's never really gonna be pretty, so why encourage it?