问题
I already know how to calculate selector specificity for CSS (the a/b/c/d mentioned in specs). However, I am having trouble figuring how to calculate it for the :not()
pseudo-class. See the following example:
input:not([type="text"],[type="password"],.someClass) {...}
input:not(#someId[type="text"]) {...}
Assuming both of them apply to one element, should these two be calculated as (0011) and therefore they should be ordered according to order of appearance? Or should the selectors inside the :not()
pseudo-class be further calculated separately, depending on which one matches, as a second step to determine the one that has precedence over the other?
回答1:
Assuming both of them apply to one element, should these two be calculated as (0011) and therefore they should be ordered according to order of appearance? Or should the selectors inside the
:not()
pseudo-class be further calculated separately depending on which one match as a second step to determine the one that have precedence over the other?
If you're implementing Selectors 3, they should not be counted at all. As already mentioned, both of your selectors are invalid according to that spec because it only defines :not()
to accept a single simple selector at a time.
If you expand them out so that they validate (following the instructions/examples given here), then their specificities will be calculated as follows:
/* 2 attributes, 1 class, 1 type -> specificity = 0-3-1 */
input:not([type="text"]):not([type="password"]):not(.someClass)
/*
* 1 ID, 1 type -> specificity = 1-0-1
* 1 attribute, 1 type -> specificity = 0-1-1
*/
input:not(#someId), input:not([type="text"])
Because Selectors 3 says:
Selectors inside the negation pseudo-class are counted like any other, but the negation itself does not count as a pseudo-class.
Also, in response to your comment:
True, according to specs, simple selectors only. But some browsers support multiple ones. Some of them don't, and some dropped them later. Also, you can write the same rule even with simple selectors like this instead:
input:not([type="text"]):not([type="password"]):not(.someClass)
which is better and work as well. Does this mean it should be calculated as 0031, then? How about those that support multiple ones, how do they calculate?
The only browser I know of that has ever supported multiple selectors within :not()
is Firefox 3.0, and it does so because of a bug. Selectors 3 never allowed :not()
to contain multiple selectors — that is only introduced in Selectors 4, for which specificity calculation hasn't even been clearly defined yet1, so even if you were trying to implement Selectors 4 (which I seriously doubt you are), you'll be stuck.
It's not clear to me how Firefox 3.0 implemented specificity with its version of the OK so I picked up Firefox 3.0 beta 1, 3.0.0, 3.0.18 and 3.1 beta 1, and none of them reproduce this behavior at all. So there you have it.:not()
selector and I don't have a copy of it to test with, but I think it's safe to assume that it doesn't matter anymore as it was never the intended behavior anyway.
1Note that both the current 2013 ED and the 2011 FPWD are consistent in saying that the specificity of :not()
is equal to that of its most specific argument, but this may change in the future.
回答2:
Logical intent
Below is a breakdown of the CSS selectors originally posted in the question. This is an attempt to summarize how both CSS rules can be expressed using valid CSS (a discussion started by @thgaskell and @BoltClock). I'll leave the question of specificity to the other posters.
First rule
input:not([type="text"],[type="password"],.someClass) {}
This is a non-validating selector in CSS3, which might not be supported by any known browsers at present.
The logical intent of the selector is !(a or b or c)
, which is equivalent to !a and !b and !c
. For CSS selectors a logical and
operation requires chaining, which can be expressed as :not(a):not(b):not(c)
.
Thus the first rule can be expressed in valid CSS as follows:
input:not([type="text"]):not([type="password"]):not(.someClass) {}
Second rule
input:not(#someId[type="text"]) {}
This is a non-validating selector in CSS3, which might not be supported by any known browsers at present.
The logical intent of the selector is !(a and b)
, which is equivalent to !a or !b
. For CSS selectors a logical or
operation requires using multiple selectors (one selector for each operand), which can be expressed as :not(a), :not(b)
.
Thus the second rule can be expressed in valid CSS as follows:
input:not(#someId), input:not([type="text"]) {}
Summary
A logical and
operation requires chaining each operand.
.a.b {} /* Matches elements with both classes */
/* (a and b) */
:not(.a):not(.b) {} /* Matches elements with neither class */
/* (!a and !b) == !(a or b) */
A logical or
operation requires using multiple selectors (one selector for each operand).
.a, .b {} /* Matches elements with either class */
/* (a or b) */
:not(.a), :not(.b) {} /* Matches elements that don't have both classes */
/* (elements with none or only one of the classes) */
/* (aka: not both, nand, alternative denial */
/* (!a or !b) == !(a and b) */
回答3:
The spec (W3C Selectors Level 3) states pretty clearly that pseudo-classes are counted the same as classes.
Some playing around with a jsfiddle in the major browsers indicates that you are correct (in your comment), and the specificity for
input:not([type="text"]):not([type="password"]):not(.someClass) {border:3px solid red}
... would be 0.0.3.1. It takes 3 class-names on a style declaration coming later to over-rule the above selector.
Given:
<input value="X" class="Y Z" id="myId"/>
You cannot override the above selector with just:
input.Y.Z{border:3px solid pink;}
See http://jsfiddle.net/mhfaust/SxavM/1/
update BoltClock is right. The spec states that "Selectors inside the negation pseudo-class are counted like any other, but the negation itself does not count as a pseudo-class." So since each selector inside of :not()
is, in this example, a class-name or a pseudo-class, the specificity remains 0.0.3.1
来源:https://stackoverflow.com/questions/15879843/calculating-css-selector-specificity-for-not-pseudo-class