Efficient Algorithm To Compare Specificity Of CSS Rules
That is determined by specificity. In this case, since they are both equally specific, the declaration that comes last in the file, wins.
Specificity Calculation
Specificity is calculated by ranking the different parts of the selector.
Ranked from most specific to least:
- Style attribute - If the rule is found in a style attribute, this rank gets 1.
- ID - For each ID found in the selector, this rank gets an additional 1.
- Classes, Pseudo-Classes, Attribute selectors - For each one found in the selector, this rank gets an additional 1.
- Elements - For each element found in the selector, this rank gets an additional 1.
Where rank n > rank n+1
, regardless of how many points each rank has.
Example
ul#nav li.active a
The points are:
- 0 - Not a style attribute.
- 1 - 1 ID found.
- 1 - 1 Classname found.
- 3 - 3 Elements found.
Therefore, each property in that selector has a specificity value of [0,0,1,1,3]
(We'll get to that extra zero in a minute). That value is more specific than any selector, as long as it might be, without an ID, for example.
Comparison algorithm:
- Go from left to right on the ranks.
- Compare the ranks on both selectors.
- The rank with the higher amount of point, wins.
- If the ranks are equal, continue right to the next (less specific) rank.
- If all ranks are equal, the one which comes later in the CSS document, wins.
More important notes:
- The universal selector
(*)
has no specificity value (0,0,0,0) Pseudo-elements (e.g.:first-line
) get0,0,0,1
unlike their
pseudo-class brethren which get0,0,1,0
- The pseudo-class
:not()
adds no specificity by itself, only what's inside it's parentheses.- The
!important
directive can be applied on a single declaration, and adds a point to a "0th" rank, which is more specific than anything
else. So in the example above, adding!important
on any rule will
bump the specificity value for that rule only to[1,0,1,1,2]
,
granting it an instant win over any other rules without!important
.
Extra Reference
See this great article on the subject
How to determine which styles go to what element
The way the browser does it, is to go over the selector from right to left, and filtering elements out of the DOM as they go.
Going back to the previous example:
ul#nav li.active a
The browser does the following:
- Take an
a
element. - Now check if it has an ancestor that is a
li
element with an.active
class (this is through the descendant combinator:ancestor descendant
). - Now check if it has a higher ancestor that is a
ul
with an ID of#nav
(again, the descendant combinator is used).
If all these conditions are met for a certain element, then the styles are applied to it.
You can read it:
Select any
a
element
with an ancestor with a class of.active
, which is also ali
,
which in turn has an ancestor with an ID of#nav
, which is also aul
.
You'll need to have a fully function and complete DOM tree to be able to successfully determine which element has what CSS styles.
How are the points in CSS specificity calculated
Pekka's answer is practically correct, and probably the best way to think about the issue.
However, as many have already pointed out, the W3C CSS recommendation states that "Concatenating the three numbers a-b-c (in a number system with a large base) gives the specificity." So the geek in me just had to figure out just how large this base is.
It turns out that the "very large base" employed (at least by the 4 most commonly-used browsers*) to implement this standard algorithm is 256 or 28.
What this means is that a style specified with 0 ids and 256 class-names will over-ride a style specified with just 1 id. I tested this out with some fiddles:
255 classes are not enough to override 1 id
...but 256 classes are enough to override 1 id
...and 256 tag-names are enough to override 1 class-name
...but, alas 256 ids are not enough to override 1 inline style (Updated 2012/8/15 -- you'll have to use
!important
)
So there is, effectively, a "point system," but it's not base 10. It's base 256. Here's how it works:
(28)2 or 65536, times the number of ids in the selector
- (28)1 or 256, times the number of class-names in the selector
- (28)0 or 1, times the number of tag-names in the selector
This isn't very practical for back-of-the-envelop exercises to communicate the concept.
That's probably why articles on the topic have been using base 10.
***** [Opera uses 216 (see karlcow’s comment). Some other selector engines use infinity — effectively no points system (see Simon Sapin’s comment).]
Update, July 2014:
As Blazemonger pointed out earlier in the year, webkit browsers (Chrome, Safari) now appear to use a higher base than 256. Perhaps 216, like Opera? IE and Firefox still use 256.
Update, March 2021:
Firefox no longer uses 256 as a base.
Order CSS based on Selector Specificity
Short answers:
Are there any existing libraries for this?
No, not one I'm aware of that does this "out-of-the-box" for you.
Or any useful libraries to help with this?
Yes, there is json_decode
and uksort
:
$specificity = function($selector) {
/*
* @link http://www.w3.org/TR/selectors/#specificity
*
* 9. Calculating a selector's specificity
*
* A selector's specificity is calculated as follows:
*
* * count the number of ID selectors in the selector (= a)
* * count the number of class selectors, attributes selectors, and
* pseudo-classes in the selector (= b)
* * count the number of type selectors and pseudo-elements in the
* selector (= c)
* * ignore the universal selector
*
* Selectors inside the negation pseudo-class are counted like any other,
* but the negation itself does not count as a pseudo-class.
*
* Concatenating the three numbers a-b-c (in a number system with a large
* base) gives the specificity.
*/
...
return (int) $result;
}
$compare = function($a, $b) use ($specificity) {
return $specificity($a) - $specificity($b)
};
$array = json_decode('{"yours" : "json"}', true);
uksort($array, $compare);
echo json_encode((object) $array);
As this code example shows, it only explains how to calculate the specificity in a comment and it does not contain the code. That's just because I don't have that code at hand, but I have put in there the specification how this is done (at least for CSS 3).
If you're looking for a CSS selector parser, I know about XDOM (because I wrote it). It's available on github: https://github.com/hakre/XDOM - It's a 100% CSS 3 compatible CSS selector parser.
To my best knowledge that is most of what you get as of today in terms of ready-made solutions. All other CSS selector parsers I know of are not compatible with the CSS 3 standard in full because they don't follow the W3C specification. Which might be good for you: If you don't need strict CSS3 compatbility, you might find some other code-chunks that suit your needs already.
Quicker of two CSS rules: with/without multiple IDs specified
Short story: the more of anything you use, the slower it is to parse.
An ID is always unique, so you should only ever use one; but even with classes, specifying any other elements or criteria is always going to be slower.
http://css-tricks.com/efficiently-rendering-css/
That article goes far more in depth into exactly what you are asking about.
speed of declaring element with class name vs. class name
Technically yes, there is a very slight difference in speed. But you don't need to worry about CSS matching speed. It's microseconds (as in millionths of a second).
What you should worry about is specificity.
See my answer here.
CSS Performance between class and attribute selectors
There is no performance issue. Both act same. But there is difference in specificity of the css with class versus Elements.
Specificity - Specificity determines, which CSS rule is applied by browsers.
If two selectors apply to the same element, the one with higher specificity wins.
But specificity has hierarchy.
- Inline styles (Presence of style in document).
An inline style lives within your XHTML document. It is attached directly to the element to be styled. E.g. - IDs (# of ID selectors)
ID is an identifier for your page elements, such as #div. - Classes, attributes and pseudo-classes (# of class selectors).
This group includes .classes, [attributes] and pseudo-classes such as :hover, :focus etc. - Elements and pseudo-elements (# of Element (type) selectors).
Including for instance :before and :after.
Source: http://coding.smashingmagazine.com/2007/07/27/css-specificity-things-you-should-know/
Hence div.test {}
is more specific.
Related Topics
Make CSS Shimmer Effect Work an Already Loaded Image
How to Have Slanted Box-Shadows Using Only CSS
Safari Print Media Queries Not Matching Other Browsers/Cutting Off
Browser as a Design Tool - Change Colors, Save Them
Why Does This Div Shift Down When Content Is Added
Limit Initial Width of Select List
Can Relative Paths Be Used for @Font-Face Src
How to Create This Irregular Quadrilateral with CSS
Overflow:Hidden Not Working as Expected in Google Chrome
Cutting a Triangle Out of Div, But Have It Horizontally Centered
How to Center Align a Child Div Inside a Parent Div with CSS
Css3 Grid Layouts: New Row After Specific Element - Possible
Why Does Fixed Positioning Alter the Width of an Element
I Need to Remove the Horizontal Scrollbar on an Overflown <Div>
Force Elements to Be Horizontally Aligned
How to Overflow the Contents of a Column into the Next Column Using CSS
Checking Hardware Acceleration Availability? (Testing Available)