Calculating CSS selector specificity for :not() pseudo-class

大城市里の小女人 提交于 2020-01-06 04:38:04

问题


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 :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. 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.


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!