Skip to content

Date: 17 April 2014



CSS Specificity, If you can say it...

...or even spell it! The concept of specificity is extremely important in CSS, but it is not too well known, and it is clouded by unnecessarily complex explanations. But if ever your CSS stylesheet contains a style that the browser appears to be ignoring for no good reason, most likely Specificity is the issue. It comes into play when more than one CSS selector matches the same HTML element on the page.

Unfortunately, most tutorials on the subject make it far more difficult than it needs to be, introducing complicated value scoring systems to assign weightings to competing CSS selectors. They do this because that is how W3C specified it in it's mathematically rigorous specification intended for the browser manufacturers, written to provide exact rules for all browsers to follow with no misunderstanding. Some developers are put off by the complexity of that approach.

But if we consider the detailed logic underlying W3C's Recommendation we can make things a lot easier for ourselves. We can find a much quicker way of arriving at the exactly same results. No value calculations needed. Forget the browser manufacturer spec.

In fact we can isolate four basic principles from the logic of W3C's Recommendation. I like to call them The Four Principles of CSS Specificity.

The First Principle of Specificity

The first principle is simple enough:

First Principle of CSS Specifity

If an HTML element has a style attribute containing inline styling, that styling overrides any contrary styling elsewhere in the CSS, except where the !important keyword has been used.

So any property set either in a stylesheet, or in embedded styling in <style> tags in the <head> section of the HTML script, will be ignored if the same property is set by inline styling on the element itself. That can only be overridden by the !important keyword (of which more later).

Example for discussion

Coming now to the more usual case where there is no inline styling, what happens in the event of conflicting CSS property settings? Take an example of three CSS selectors all wanting to set the text colour, and all matching the same particular div. Which selector - and therefore which bunch of styles, will the browser use?


    #blueThing  { color : blue; }
    .greenThing { color : green; font-size: large; text-align: right; }
    div         { color : red; text-align: center;}

and the HTML:


    <div id="blueThing" class="greenThing">
      An example to demonstrate a new approach to CSS Specificity
    </div>

This div fits all three CSS selectors, resulting in 3 conflicting colours for the text of the div. Some developers would assume the text will be red, because that's the last rule in the stylesheet. But they would be wrong.

The Second Principle of Specificity

In any situation, like our discussion example, where two or more CSS rules have conflicting property settings, we have to to look at each of the selectors involved and identify its component parts. Selector components fall into one of three groups, listed here in order of decreasing importance:

  • ids
  • classes, pseudo-classes, and attributes
  • elements and pseudo-elements

These groups have a priority over each other, or a weight, if you prefer, that decides which one of multiple selectors will apply in any given case of conflict. Ids outweigh classes, and classes outweigh elements. Within a group the weight is the same; for instance attributes (in the second group) have the same weight or priority as classes and pseudo-classes.

The nice bit is that, far from having to tediously calculate values or weights for each component in each conflicting selector, if one selector contains even just one id more than the others, then it is completely irrelevant how many classes, attributes, elements or anything else the other selector contains.That one id trumps the lot!

If, however, two selectors have the same number of ids, then we have to look at any components from the second group in the list - classes and attributes. But it is only the count that matters - no need to calculate anything. If one selector has more than the other then, as before, we can completely ignore the last group of components, the elements! We just don't have to think down to that level.

Putting it more rigorously, the logic in W3C's Recommendation about specificity boils down to a second principle that can be stated thus:

Second Principle of CSS Specifity

If two or more CSS selectors, that match the same target element or pseudo-element, contain conflicting settings of a particular style then:

  • the style is set from the selector containing the most ids.
  • if no one selector contains more ids than the others, then the selectors with fewer ids are ignored and, from the remainder, the style is set from the selector containing the most classes and/or pseudo-classes and/or attributes.
  • if no one remaining selector contains more classes, pseudo-classes and attributes than the others, then the selectors with fewer of those components are ignored and, from the remainder, the style is set from the selector containing the most elements and/or pseudo-elements.
  • the universal selector *, and the negation :not() are ignored - they have zero specificity.

All styles that only occur under any one of the selectors, and therefore have no competitor, will be applied as normal.

So first we look at the number of ids in the selectors. If they identify one selector as having precedence, we need look no further, saving ourselves a lot of work. Only if that isn't enough do we count the number of classes, pseudo-classes and attributes. And only when that is still not sufficient do we need to go down to the element/pseudo-element level.

So suppose we had four competing selectors, two with 2 ids each, a third with 1 id, and the last with no ids at all, and all of them try to set the background. We can see immediately that the winning selector will be one of the first two; the last two have already lost out by having fewer ids. Yes, we will have to count up classes and attributes to decide the ultimate winner, but not in the two selectors that we can already see have lost at the earlier stage.

As to what happens if the number of elements is the same as well (in other words the two or more selectors have exactly the same specificity), wait for the third principle below.

The Second Principle in Action

Suppose we have the following HTML markup:


     <div id="myId" class="red myClass">....</div> 

and if the following (somewhat artificial) list of selectors in the CSS all match this div:

Example 1

  1. div#myId span {color:green}
  2. div#myId.mainClass.myClass {color:red}
  3. div.myClass div#myId[title]:hover::before {color:skyblue}
  4. #container div#myId {color:orange}
  5. .mainClass {color:gray}

The selector that takes precedence here is (4) because it contains two ids while the others only have one or, in the case of (5), none at all. Selector (3) contains all sorts of stuff, but none of it is relevant apart from its one id, which isn't enough to make it the important one. So the text will be orange, taken from (4).

Now suppose instead that we have the same selectors but with all the ids removed. How will it work now?

Example 2

  1. div span {color:green}
  2. div.mainClass.myClass {color:red}
  3. div.myClass div[title]:hover::before {color:skyblue}
  4. div {color:orange}
  5. .myClass {color:gray}

With no ids, we now have to delve down to the next level of priority, classes. Selector (2) has 2 classes, but (3) has 1 class plus 1 attribute plus 1 pseudo-class, i.e. three components from the second of our three groups listed above. (It also contains 2 elements and a pseudo-element, but they are a lower level of importance so would only be important if all the selectors had the same number of class-level components). So (3) wins, and the colour will be sky blue.

From these examples it can be seen how quick it is, even in very complex situations, to identify the selector that takes precedence, without any kind of complicated scoring.

Back to the Example

So back to our original example above. The CSS selector containing the simple div element (and which says the text should be red) is overruled by the selector containing the class component .greenThing, even though the Div selector came after the class selector in the stylesheet.

But that in turn is overruled by the selector containing the id, #blueThing, which demands that the text be blue.

The font size, on the other hand, will be large, taken from the .greenThing selector. Font size occurs in only one of the three selectors, so experiences no conflict.

Coming now to the text-align property, everything changes again. Since the blueThing rule doesn't set the text-align, it plays no part in this even though it was the most important one for setting the colour. Of the two selectors trying to set text alignment, the greenThing one contains a class, which overrules the simple div selector. So text-align will be set to 'right'.

Just to emphasise one thing again, we only need to go through this process when:

  1. two or more selectors match the same element or psuedo-element
  2. and they both contain at least one style (property) that is the same in both
  3. and they have different property values

For most of our work specificity will not be an issue.

The Third Principle of Specificity

The third principle is another straightforward one:

Third Principle of CSS Specifity

If two selectors in a web page are equal under the second principle, then the one that comes last in the CSS styling is the one that will be used in the event of any conflict.

It is wise, however, not to rely on order of appearance in a style sheet. If you (or some successor to you on a business site who doesn't know what you intended) move things around, perhaps on the addition of more styling, or even just to tidy it up, your reliance on ordering could be broken, and this might go unnoticed for quite a while. Rather than do this it is better to add another item into the selector you want to have precedence (more on this below). The existence of apparently excess components in a selector should make another developer stop and think; it may be there for specificity reasons. But the order of styling gives no indication that that order is critical.

However CSS3 media queries, used in Responsive web development, are frequently written in a way that relies on the Second Principle, because media query writers understand that such queries must be treated as a set, keeping the order as written if required. A media query that applies beyond a certain screen width does not mean the rules it contains will definitely be applied. It merely makes those rules available for consideration at the specfied screen width. Its rules must still fight with any other CSS rules, if any, that are applicable at the same screen width and match the same target elements, according to the normal principles of specificity.

This Third Princple mentions "styling" rather than "stylesheet" because it can be used across a whole collection of stylesheets, however many there may be in the page. But in a complex page of multiple linked and imported stylesheets we need a Forth Principle to clarify the order in which they apply.

The Forth Principle of Specificity

The forth principle is not about selectors, but about the various documents holding them, including:

  • linked stylesheets (linked to an HTML script using the <link> tag)
  • stylesheets imported into another stylesheet or the HTML script using the @import command
  • and styles embedded internally in the HTML script inside <style> tags.

The browser must search all of these to find all the selectors that match each element in the HTML.

The forth principle simply states in what order the various stylesheets must be considered, so we can see which selector comes last for purposes of the Third Principle:

Forth Principle of CSS Specifity

In a single web page, the CSS found in different documents is loaded and implemented according to the following rules:

  • any default CSS rules set by the browser are applied first
  • presentational elements, and attributes of elements, in the HTML markup (e.g. width, bgcolor, <s> etc), are converted to the equivalent CSS properties and assigned zero specificity (since they have no selector) and parsed immediately after the browser's default styling, before any stylesheets
  • any styling contained in a stylesheet imported using @import is applied at the point of import
  • any styling contained in a stylesheet linked using <link> tags is applied at the point of linking
  • styling embedded inside <style>...</style> tags in the <head> section is parsed in it's actual position, which may be before, between, or after any linked stylesheets

If two selectors anywhere in the CSS are of equal value under the Second Principle, then these rules indicate which of the two selectors is last for purposes of the Third Principle.

This might seem a lot to take in, but if you look at it carefully, it's all actually common sense; most of it is the order we would probably expect naturally without being told. Putting it in the form of a formal principle merely provides a clear point for reference. The reason for this behaviour is that that browsers parse each block or document of CSS in the order they come to them, and then use the data from each one to build up a tree of property settings for each HTML entity according to the rules. Where the browser finds that a property it wants to add has already been set in the tree, it simply overwrites the value already there.

What it boils down to is, if a selector takes precedence under the Second Principle, it does not matter in which of many stylesheets or embedded styles it is situated. But if two selectors, anywhere in all the CSS, have equal value under the Second Principle, then this Forth Principle tells us which one comes last and so takes precedence under the Third Principle.

The Forth Principle in Action

For example, since any imported CSS simply replaces the @import rule where it is, if a stylesheet imports two - or twenty - other stylesheets then they will be parsed by the browser in the order they are imported. And the subsequent styling in the sheet that imported them is parsed after all the imports (because any @import command has to be at the top of the stylesheet to be valid).

Likewise if there are several linked stylesheets, the styling from each one (including any imported styling they may have) is parsed after the stylesheet from the previous link.

Take the following example of several stylesheets, all specifying a different text colour, but all for the #myId selector so the Second Principle of Specificity doesn't help us; all these selectors have equal weight:


    #s In 1.css: #s
        @import 2.css
        @import 3.css
        #myId {color: red;}
        
    #s In 2.css: #s
        #myId {color: orange;}
        
    #s In 3.css: #s
        #myId {color: yellow;}
        
    #s In 4.css: #s
        @import 4.css
        #myId {color: green;}
        
    #s In 5.css: #s
        #myId {color: blue;}

and the HTML:


        <html>
        <head>
        <link href="1.css">
        <style>
            #myId {color: indigo; width="25%"}
        <style>
        <link href="4.css">
        <style>
            #myId {color: violet; width="25%"}
        <style>
        </head>
        <body>
        <div id="myId" style="color: gray" width="50%">.....</div>
        </body>
        </html>
    

The text colour starts off black - that's the default in all browsers (unless the user changed it). In the unlikely event of legacy HTML containing an old, now deprecated, font tag saying <font color="white">, then that would be placed next in the sequence, overriding the black colour.

But if we now read through the HTML we come to the first link to an external stylesheet, 1.css. Following this link we find 1.css first imports 2.css, which sets the text to orange. Then comes another file import, of 3.css, which changes the text colour yellow. But after doing the two imports at the start of the stylesheet, then 1.css itself sets the colour yet again in its own content, this time to red.

We now come back out to the HTML script, and find some styling embedded in the HTML after the stylesheet link. This changes the colour to indigo. But then we find another linked stylesheet, which in turn imports another one, both making further colour changes! When we come out of them back to the HTML, there is more embedded styling, now making the colour violet.

Up to this point, the numerous stylesheets have each superceded the previous one, and each would have resulted in a new colour had they in turn not been overridden by a later one. But even the violet colour doesn't last long, because a final change is made by the inline styling in the HTML body which, in line with the First Principle, makes the text in this div grey - a sad ending after such a colourful history, but I hope it makes clear at what point each selector takes effect!

Note that the second list item in the Forth Principle allows for presentational elements or attributes in the HTML markup, as in: <div width="80">. Such HTML markup is of course strongly deprecated in favour of using CSS, but if you are adding CSS to a legacy HTML program that contains such attributes, they are assigned zero specificity by the browser, so you can go ahead knowing that whatever you put into the stylesheet will automatically override them. And of course the new HTML5 canvas element requires it's height and width to be specified in the HTML, but its dimensions can easily be altered in the CSS.

Note that, as with earlier examples, we could have made any one of the earlier colour settings take precedence over all the others by adding another component to the relevant selector. For instance, in 2.css:

 div#myId {color: orange;} 

Here, simply adding the div is enough to bring the Second Principle into play, and giving this selector precedence and so making the text orange, overriding all the other settings in all the stylesheets.

!Important declarations

Finally there is the matter of styles marked !important (some would say this is not strictly a part of "specificity" as such, but it can override the rules of Specificity and so deserves discussion here - as it has in W3C's pages on Specificity.) The rules for !important style settings are:

  • A property setting tagged as !important overrules all normal, non-!important settings of the same property, regardless of selector and which document they may be in.
  • !important styles even override inline styling.
  • A property setting marked !important in the user's stylesheet overrides !important settings of the same property in the developer's stylesheet.
  • Declaring a shorthand property (e.g. 'background' or 'font') to be !important is equivalent to declaring all of its sub-properties to be !important, including any sub-properties omitted from the shorthand and therefore set to their default initial values.
  • If two or more settings of the same property, that match the same target element (or pseudo-element), are marked as !important but contain conflicting property values then which one applies will depend on which parent selector takes precedence according to the normal Four Principles of CSS Specificity.

However it is advisable to not use !important in a developer's stylesheet more than absolutely necessary. W3C primarily intend it to be used for Accessibility, to enable users who need special size, colour, or other property settings to override anything the developer has set.

One valid use of !important style settings, however, is to override badly written external plugins that have used inline styling (I have been told jQuery has a few of these, but correct me if I'm wrong), where you may not wish to (or don't have access permissions to) amend the plugin's markup.

And some mopping up

Let's just clarify certain particular situations and questions that can arise, so we've covered all bases (click on each one for further details):

When counting up component numbers for the Second Principle ignore all operators.

Operators include , : + > [] () ~ | and =

If a component occurs several times in a selector, it is counted each time.

A case of nested divs might have: div div div { border: 1px } to give the innermost box a border. This counts as 3 elements in the selector, so it would overrule any more general rule you might already have to stop divs having borders such as: div { border: 0 }.

If you accidentally include the same CSS rule twice in the spreadsheet, then the last instance will be used.

In short, it follows the Third Principle. So in this example the padding will be 3em, from the last rule:-

    .box { padding : 1em }
    .box { padding : 3em }
    
Although the negation pseudo-class :not(...) does not count as anything and should be ignored, whatever is inside it does count.

So: button not( [title]) {...} (meaning buttons that do not have a title attribute in the HTML markup) counts as 1 element (button) plus 1 attribute (title) in the selector.

In the particular case of an attribute selector referring to the id attribute, as in [id='main-div'], the component still just counts as an attribute

An attribute is in the second group mentioned in connection with the First Principle. That it just happens to specify the id attribute has no relevance to specificity.

Selectors grouped in a list and separated by commas, as in #box1, #box2, #box3 {...} are treated as separate selectors for Specificity.

So this example does not have 3 ids in it, but is three independant selectors each with one id (and each could therefore be overridden by another selector containing 2 ids). They actually refer to different objects on the page and have merely been listed together in a shorthand notation for convenience, because they happen to want the same styling.

If a property short-cut is declared without assigning values to all the expected sub-properties, the unassigned ones will be given default values, which must be taken into account in understanding the specificity situation.

E.g a developer might easily do this, thinking they will get bold text:-

p.warning {
            font-weight: bold;
            font: 20px Arial;  
        } 

but in fact the font-weight will be normal, not bold, because in the font short-cut setting the font weight has been omitted and therefore gets set to the default initial value, which is normal; and the Third Principle finds this short-cut after the bold setting.

Browser bugs in Specificity

Some early browser versions had their usual array of bugs or partial implementations of specificity, but by IE7 I know of only one specificity bug. It was fixed in IE8.

and also some reminders:-

Make sure your spaces are correct; a space in a selector is the 'has descendant' operator

For instance, div#myId means a div with the specified id, whereas div #myId means an element with the specified id that is the child of a div.

If you delete HTML elements from your web page...

If they carry an id or class, search for all occurrences of these in the CSS, because those selectors will now no longer work!

Please note that I have not considered styles set by the user in their browser, as this article is intended for developers.

Good CSS Practice

We have already mentioned that it is good to avoid relying on the order of selectors in the CSS; add an extra component instead, to increase specificity.

Another aspect of good CSS practice is to always have as few components in your selectors as is necessary to achieve your goal. It's called keeping the specificity as low as possible. Longer selectors, with more components, firstly makes your CSS more difficult to follow and maintain, especially where elements are caught by multiple selectors. It also makes enforcing your will more complicated.

For instance, if you have a div with an id, it is not necessary to write div#myId as the selector. Just #myId is quite sufficient.

Then if, later, you want another id selector to override it, it will merely be necessary to add 'div' into the second selector to make: div#secondId. But if the first selector already has 'div' in it, then overriding it might become more difficult. You might have to add a second id into the new selector. But if there isn't a suitable id on, say, the parent element, you might have to add an id into the HTML markup for no other purpose than your weighting requirements!

The moral is, if you diet in your CSS then weight won't be a problem (very sorry, couldn't resist that!)

Enforcing Your Will

Now some other practical uses of all this. If we are writing a selector that won't be considered because another already existing selector will overrule it, the solution is to increase its specificity by adding more components into the selector. If you see someone else's stylesheet and wonder why a particular selector has more components than seem necessary, it might be due to inexperienced programming, but it could in fact be that components have been artificially added to increase the specificity.

For instance, suppose we want to show an important paragraph in red, but suppose this paragraph is contained in a div for which we have already specified green text for paragraphs using an id:


        div#myDiv p { color : green }
        p#myP { color : red }

Now this is not intuitive; we would expect specifying this paragraph by its id (and last in the CSS as well) would be sufficient to make it red. In fact the first rule will take precedence because of the two elements in its selector, while the other has only one. (This is a good example of what we said in the last section; if the first selector had no div in it there would not have been a problem in the first place!) To force the red colour we can add another element to the second selector, e.g. div p#myP (because the p element is inside the div):-


        div p#myP { color : red }

Will adding this id to the red selector be enough? Well, yes, both selectors now contain 1 id and 1 element. But this now relies solely on the order of the selectors in the stylesheet. We can do better; add an id (assuming this is the only paragraph we want in red):


        #myDiv p#myP { color : red }

Now the red case has two ids, and wins. We have increased its specificity to be more than the other one, and did it safely. Of course, what we can add to the selector will depend on the structure of the page. If the paragraphs weren't in a div, we would have to look for something else to use.

Summary

The above Four Principles of CSS Specificity are based entirely on the logic contained in W3C's official Recommendations, which all modern browsers have followed. The Four Principles make clear, in any given circumstance, which style will apply to an element in any case of multiple conflicting styles.

So, forget value scoring systems. I hope these four principles will simplify the process. You just need to look for the most important components in each conflicting selector to see immediately which one wins!

References:

By Guy Hickling

I would welcome your thoughts on this subject...



Please speak your heart here:-

- No need to prove you're a human being. I'll just take your word for it.

We can isolate four basic principles from the logic of W3C's Recommendation. I like to call them The Four Principles of CSS Specificity.
All content on this site is the copyright of the author