Efficient Algorithm to Compare Specificity of CSS Rules

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:

  1. Style attribute - If the rule is found in a style attribute, this rank gets 1.
  2. ID - For each ID found in the selector, this rank gets an additional 1.
  3. Classes, Pseudo-Classes, Attribute selectors - For each one found in the selector, this rank gets an additional 1.
  4. 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:

  1. 0 - Not a style attribute.
  2. 1 - 1 ID found.
  3. 1 - 1 Classname found.
  4. 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:

  1. Go from left to right on the ranks.
  2. Compare the ranks on both selectors.
  3. The rank with the higher amount of point, wins.
  4. If the ranks are equal, continue right to the next (less specific) rank.
  5. 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) get 0,0,0,1 unlike their

    pseudo-class brethren which get 0,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:

  1. Take an a element.
  2. Now check if it has an ancestor that is a li element with an .active class (this is through the descendant combinator: ancestor descendant).
  3. 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 a li,

which in turn has an ancestor with an ID of #nav, which is also a ul.

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.

  1. 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.
  2. IDs (# of ID selectors)
    ID is an identifier for your page elements, such as #div.
  3. Classes, attributes and pseudo-classes (# of class selectors).
    This group includes .classes, [attributes] and pseudo-classes such as :hover, :focus etc.
  4. 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



Leave a reply



Submit