6

For example to style standard inputs I write something like:

input:not([type="checkbox"]):not([type="radio"]) {
    background-color: blue;
}

However that increases the specificity a lot so if I want to override it using a class I have to do something like:

.red.red.red {
    background-color: red;
}

Is there a way to decrease the specificity of the original input selector without changing the functionality?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
joshhunt
  • 5,197
  • 4
  • 37
  • 60

2 Answers2

4

Unfortunately, in Selectors 3, that's the best you can do since :not() only accepts a single simple selector. Having said that, the selector in your overriding rule can be replaced with input.red.red — you don't need more class selectors than attribute selectors unless that rule has to appear earlier in the stylesheet.

This is another problem that Selectors 4 solves with its enhancement of :not(): specificity. In Selectors 4, you will be able to replace all those negations with just one :not() pseudo, effectively decreasing its specificity within your original selector to just one attribute selector. From section 16:

The specificity of a :not() pseudo-class is replaced by the specificity of the most specific complex selector in its selector list argument.

Since any attribute selector is equally specific to a class selector, the specificity of any number of lone attribute selectors in a list will never be more than that of just one of them. This allows you to get away with using just one class selector for your override without having to repeat it.

The following works in Safari as a proof-of-concept:

/* 1 type, 2 attributes -> specificity = (0, 2, 1)
input:not([type="checkbox"]):not([type="radio"]),
   1 type, 1 attribute  -> specificity = (0, 1, 1) */
input:not([type="checkbox"], [type="radio"]) {
    background-color: blue;
}

/* 1 type, 1 class      -> specificity = (0, 1, 1) */
input.red {
    background-color: red;
}
<input type="checkbox">
<input type="radio">
<input type="text">
<input class="red" type="text">
Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
1

This may get you around the specificity issue:

input:not([type="checkbox"]):not([type="radio"]):not(.red)) {
    background-color: blue;
}

.red {
  background-color: red;
}
<input type="checkbox"><br>
<input type="radio"><br>
<input class="red">
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    It's creative I'll give you that :D. Unfortunately it's not very practical as you want `.red` to still inherit the original styles but with the ability to override the original styles. My example didn't show this, sorry. – joshhunt Mar 08 '17 at 20:42
  • 1
    Yeah, I didn't know all the details, so I threw in a concept. I knew it was a long-shot. – Michael Benjamin Mar 08 '17 at 20:48
  • Thanks, I appreciate the effort! – joshhunt Mar 08 '17 at 20:53
  • This is invalid - you cannot nest multiple :not()s within one another, not even in L4. – BoltClock Mar 09 '17 at 02:39
  • @BoltClock, that was a typo. Needed a closing bracket. Not intending to nest :`not()`s. – Michael Benjamin Mar 09 '17 at 02:42
  • Wait... when did they remove the restriction? I had no idea. So :not([type="radio"]:not(.red)) *is* valid. How about that... – BoltClock Mar 09 '17 at 02:44
  • Ha, I never new it was restricted. I've always known `:not()` to be able to chain together. But your comment led me to identify a missing bracket, which indeed created a nested `:not()`, which is invalid. @BoltClock – Michael Benjamin Mar 09 '17 at 02:47
  • 2
    L4 :not() *is* designed to solve the specificity problem though. Check out my answer. (To be honest [I bugged joshhunt into posting this question](http://chat.stackoverflow.com/transcript/message/36005827#36005827) as we were discussing it on chat just yesterday...) – BoltClock Mar 09 '17 at 03:12
  • 2
    Look at that entire world I didn't know about. Now I can see how incredibly out-of-context my answer is ;-) @BoltClock – Michael Benjamin Mar 09 '17 at 03:47