Priority of CSS selectors

9 Abr 2014

We usually build our sites using third-party CSS (bootstrap, a CMS theme, etc.), and some selectors and properties might be overriden.

There are mainly three ways to define styles in our web, but the browser will give higher priority to the selectors and properties is this order:

1. External files set in withing the <head> tag
2. Properties in the <style> section
3. Inline properties within an HTML element with style=""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Type 1 -->
<head>
    <link rel="stylesheet" href="#" type="text/css" media="all">
</head>

<!-- Type 2 -->
<style>
    p {
        margin-bottom: 10px;
        color: red;
    }
</style>

<!-- Type 3 --> <!-- You'll burn in hell if you use this with no reason -->
<p style="margin-bottom: 10px; color: red;">

While using methods 1 and 2, CSS properties are set by selectors, being .class, #id, and tag the most used ones. In order to set properties to an element that is being referenced by multiple selectors, CSS is again based on priorities: the highest rank the selector gets on a given formula, will be the one defining CSS properties, and the losing selectors’ properties will be overriden. The formula is calculed as follows:

a = Inline style (type 3)
b = Number of ids (#) on the selector
c = Number of classes (.) and pseudo-classes[1] on the selector
d = Number of HTML tags on the selector
Formula: 1000*a + 100*b + 10*c + d

The selector with the highest rank wins[2], in case of tie prevails the one which is defined later in the CSS file. Operators like >‘ and ‘~‘ either add or sustract points in the formula:

1
2
ul li { ... }     /* Rank: 2 */
ul > li { ... }   /* Rank: 2. Latest declaration -> Wins */

We can also use the !important declaration, which gives the highest priority to that property, but it’s said to be not clean enough, hence it’s recommended to declare with classes and ids as many HTML elements as we need.

Some examples to make this clear:

1
2
3
4
5
6
ul li { ... }                             /* Rank: 2 (1 + 1) */
.red { ... }                              /* Rank: 10 */
#myID { ... }                             /* Rank: 100 */
#myID .red { ... }                        /* Rank: 110 (100 + 10) */
#myID .red div > ul { ... }               /* Rank: 112 (100 + 10 + 1 + 1) */
#myID .red div li:first-child { ... }     /* Rank: 114 (100 + 10 + 1 + 1 + 2) */

[1] Pseudo-classes: [class*=”red”][type=”button”], [id=content]. The last one, even referring an id, counts as a pseudo-class selector.
[2] It’s not really a 10-base sum, as a selector with 11 HTML tags has less priority than one class selector, but you do have a problem if you use a selector that huge 🙂