css specificity/the battle for dominance

February 20, 2008 / 12:53

css is built around the struggle for dominance. The whole concept of css is constructed around cascading, better known to most people as the waterfall principle. While many people understand this principle, the exact details of the way css is applied in real life are usually a bit fuzzy. So no better time than the present to freshen up on css and the specificity of css selectors.

the fight for dominance

css specificity and exactness

css specificity is a misleading concept. If we look at the definition of specificity, the following is probably the most common interpretation:

The exactness with which a vocabulary term covers a concept.

Although it does cover the way css specificity is implemented, it is easy to misunderstand or misinterpret this definition. The "exactness" of css is a little different than you might expect at first glance.

css has more than one way to target a single html element. It can be done through ids, classes, pseudo-classes, the html elements themselves, through css selectors or even inline. All these ways carry a different weight of importance. So it makes a great difference whether you target a div through its class instead of its id. This weight is crucial when the "exactness" of a css rule if computed.

calculating specificity

Each selector carries a weight that represents its specificity. The sum of all these values is the computed weight for a selector, based on all elements within the selector. A little overview of the possible weights:

  • 1,0,0,0 : inline styles
  • 0,1,0,0 : ids
  • 0,0,1,0 : classes, pseudo-classes and attributes
  • 0,0,0,1 : elements and pseudo-elements
  • 0,0,0,0 : the * (universal selector)

Completing this list are inherited properties and combinator, which carry no weight at all. This is different from the universal selector, which will still overwrite inherited properties.

It is possible that certain elements are targeted by more than one selector carrying the same weight. In this case, the selector appearing last in the source will take preference. An important rule which the whole concept of conditional comments is based on and which should be abused when dealing with IE6 faulty selector implementation.

9+1 is not 10

Something that got me confused at first is the fact that these calculations are not made in base-10. For example, you cannot get 11 classes to overwrite 1 id. Hence the representation of the values with "," which helps to clear up some possible confusion. All specificities are simply added within their respective weight category and the results is then compared to other selectors. A few simple examples:

h1 (weight: 0,0,0,1 ) * h1 (weight: 0,0,0,1 ) .class #id #id2 p (weight: 0,2,1,1 ) #id2 #id p .class (weight: 0,2,1,1 ) .class.class2>*~p (weight: 0,0,2,1 )

important addendum

h1 {color:#c0c0c0 !important;}

The !important declaration is a nasty little back door in the css specificity rules. By declaring something !important you fix that value as unchangeable. No other rules can change this property, no matter what their specificity is. Use this statement with caution, and don't abuse it when you are too lazy to find out which rule is holding your declaration back. !important should only be used within user style sheets or when delivering a piece of code that cannot be overruled by others. Apart from that, avoid it.

past articles revisited

In the end, css specificity is not all that difficult although it can be somewhat confusing. It plays a small role in the choice of class versus id as a targeted id can never be overruled by a string of classes in css. It plays another role in the ordering of css rules in combination with the nasty IE6 double class bug, as this bug has a huge effect on the specificity of a css rule (since classes are ignored and are not computed in the final value). Important things to consider when writing css.

I hope this brought some light in the darkness for some of you. It's all quite straight-forward but unless you're aware of all the details css specificity can be quite surprising.

blog archive

All my articles are neatly filed inside the archive. Search and filter your way to the article you like:

contact me

If you want to leave me a quick message or you have any questions, drop me a note.

Comment author
3 comments in total
January 07, 2009 20:20

One point on your important addendum. Yes, it overrides all other CSS, unless those rules also have an “!important”on them. In the example:

span.aay { background: black !important; }
.bee { background: white !important; }

span.aay will have precedence over .bee because it has higher specificity and an “!important

Important should be avoided at all costs except for quick testing (but remember to remove it later!). If you need to keep the style and you need to override some other style, it's nearly always possible to increase the specificity of the rule you're creating without resorting to important in the end.

And putting important on an inline style is an absolute no-no! That makes it impossible for an end user or agent to override the styles for accessibility or other purposes.

January 08, 2009 09:14

Good additions John, thanks for the heads up :)

Vix
March 11, 2010 22:50

I thought I understand this but obviously have it wrong - I wanted to color rows in a table differently this is how the code was set up

td{ background-color:#CCC; } .altRow{ background-color:#fff; } I applied the class to the <tr class="altRow"> but the td background color overrules I know what I have to do to fix it

tr.altRow td{.... but I don't understand why shouldn't the class overide the td? Thanks Vix

* required fields

Leave your data
Leave a comment