The Quick Guide to CSS Specificity
CSS is pretty easy to get into, mainly due to the simple nature of its syntax. It’s clear and easy to understand. It’s so simple, that anyone could style a basic website within a first few hours of learning it. But first impressions can be missleading. Writing CSS without the firm grasp of CSS specificity. the concept can lead to a messy and hard to maintain style sheet.
Understanding how CSS specificity works is a fundamental skill. Something that will enable you to write easy-to-read, clean and maintainable CSS.
Say goodbye to wasting your time scratching your head as to why the styles you applied to a specific element aren’t taking effect.
CSS specificity
If multiple CSS selectors are targeting the same HTML element, and if the CSS selectors are trying to assign the same property/properties to the HTML element, the selector with the highest specificity value will “win” and take effect.
In other words, the most specific selector gets to assign its property values to the HTML element.
Let’s look at an example:
In the example style sheet above we’re looking to style our imaginary paragraph. There are numerous ways to target our paragraph using CSS selectors and as you can see in the example, we’ve added four style rules that can get the job done.
Since all four style rules are trying to assign a colour property value to the paragraph tag, the browser gets confused so it needs a way to determine which of the declarations should be applied. The way the browser makes the decision is by calculating each selectors specificity value and then compares them to check which among them is the hightest.
The selector with the highest specificity value wins and it’s declarations get applied to the HTML element.
Here are our rules one more time with their specificity values, in order from most specific to least specific.
Selector | Specificity value |
---|---|
body#home .container p | 112 |
div#caution p | 102 |
div.warning p | 22 |
p | 1 |
So our paragraph is white.
Calculating CSS Specificity
The result of CSS Specificity calculation takes the form of four comma-separated values a,b,c,d where the values in column “a” are the most important and those in column “d” are least important. A selector’s specificity is calculated as follows:
- If the element has inline styling, add “1” point to column “a”. It automatically wins (1,0,0,0 points)
- For each ID value, add “1” point to column “b” – (0,1,0,0 points)
- For each class value (or pseudo-class or attribute selector), add “1” point to column “c” – (0,0,1,0 points)
- For each element reference (or pseudo-element), add “1” point to column “d” – (0,0,0,1 points)
You can generally read the values as if they were just a number (like we did in our example above), like 1,0,0,0 is “1000”, and so clearly wins over a specificity of 0,1,0,0 or “100”. The commas are there to remind us that this isn’t really a “base 10” system, in that you could technically have a specificity value of like 0,1,13,4 – and that “13” doesn’t spill over like a base 10 system would.
I know it sounds too technical, but believe me it’s not. Let’s take a look at a few examples to make things clearer.
<tr”>.float-left10 (one class selector – 0,0,1,0)
Selector | Specificity value |
---|---|
* { } | 0* |
li { } | 1 (one element – 0,0,0,1) |
body#home div#featured p.text | 213 (two id selectors, class selector, 3 HTML selectors – 0,2,1,3) |
li:first-line { } | 2 (one element, one pseudo-element – 0,0,0,2) |
ul li { } | 2 (two elements – 0,0,0,2) |
#footer *:not(nav) li | 23 (one id, two elements – 0,1,0,2)** |
ul ol+li { } | 3 (three elements – 0,0,0,3) |
h1 + *[rel=up] { } | 11 (one attribute, one element – 0,0,1,1) |
ul ol li.first { } | 13 (one class, three elements – 0,0,1,3) |
li.last.featured { } | 21 (two classes, one element – 0,0,2,1) |
style=”” | 1000 (one inline styling – 1,0,0,0) |
div p.big-text { } | 12 (two HTML selectors and a class selector – 0,0,1,2) |
#author-name { } | 100 (one id selector – 0,1,0,0) |
body #blog-list .post p { } | 112 (id selector, class selector, 2 HTML selectors – 0,1,1,2) |
navbar ul.menu li#first a:not(:visited) { } | 133 (id selector, 2 class selectors, 1 pseudo-class, 3 HTML selectors – 0,1,1,2) |
Notes
- * The universal selector (*) has no specificity value (0,0,0,0)
- ** The pseudo-class :not() adds no specificity by itself, only what’s inside it’s parentheses.
- The !important value appended a CSS property value is an automatic win. It overrides even inline styles from the markup. The only way an !important value can be overridden is with another !important rule declared later in the CSS and with equal or great specificity value otherwise.
- If you have 2 or more rules with same specificity value (for example you wrote the same rule multiple times in your style sheet), then the last rule will be applied.