Have you ever taken a minute to consider how does a css parser handles the priority of all of the css declarations? This might be just the right moment! This knowledge will help you avoid many problems along the way, such as using the css !important rule.
C stands for Cascading
The first step in CSS processing is combining different stylesheets and resolving conflicts between CSS declarations: this process is called cascading. There are three main principles and each of them is of different weight here:
Importance > Specificity > Source order
Importance
- User !important declarations
- Author !important declarations
- Author declarations
- User declarations
- Default declarations specified by the browser
User declarations are the ones that the user of the browser makes, for example, if he changes the default font that the browser declares. The author declarations are the ones that you, as a developer, make. A rule called !important can be added to your declaration to increase its importance. Even if using it seems tempting, it could seriously damage the readability of your code and lead to a situation later in the development when you want to change the style of something and you can’t figure out why it doesn’t work. It is better to deal with situations like that on the level of specificity.
Specificity
If two rules share the same level of importance, then the specificity is taken into account. Best way to understand it is to imagine it as a number of some sort. The order of digits is as follows:
- Inline styles
- IDs
- Classes, pseudo-classes, attribute selectors
- Elements, pseudo-elements
If the number of IDs is the same, then the number of classes is taken into account. If that won’t be enough, the number of elements is considered. For example:
#app-wrapper .articles article:hover = (0, 1, 2, 1)
It does not directly translate to a number 121 because even 11 classes are still less specific than one ID = (0, 1, 11, 1). Let’s define the specificity of different selectors here:
1 2 3 |
<div id="button-wrapper" class="button-wrapper"> <button id="button" class="button" />CLICK</button> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
* { background-color: black; } #button-wrapper .button { background-color: red; } .button:hover { background-color: green; } #button { background-color: blue; } div#button-wrapper .button[type="submit"] { background-color: orange; } |
selector | inline | IDs | classes | elements |
---|---|---|---|---|
* | 0 | 0 | 0 | 0 |
#button-wrapper .button | 0 | 1 | 1 | 0 |
.button:hover | 0 | 0 | 2 | 0 |
#button | 0 | 1 | 0 | 0 |
div#button-wrapper .button[type="submit"] | 0 | 1 | 2 | 1 |
Hey, that actually means, that the button won’t change the color on hover at all! All other selectors are more specific than .button:hover
That’s one of the reasons why I never use IDs while styling and I advise you to do the same. At some point, you might discover, that in order to change anything, you need to add IDs both to the elements in HTML and your css selectors very often. You can also easily deduce that the inline styles carry the most weight and are the most specific. Also, notice that the universal selector * has no specificity value: that means that every other selector will be more specific.
You might fall into another pitfall here as well. While the default type of the button is submit, the selector won’t apply to it unless you specifically state the type. That means, that our last selector wouldn’t even matter at all.
css important
If you feel the urge to use the !important rule for whatever reasons, hold your horses. The case might not be a total disaster yet! You can easily put this knowledge into practice.
1 2 3 4 5 6 7 |
.button { background-color:red; } .button.button { background-color: green; } |
In the second selector, you are actually looking for an element that has both .button and .button class – it does not need to have it twice. Therefore, the specificity of the second selector is increasing. Bang, problem solved! Especially if you avoid using IDs in your selectors. That does not mean that it is a good practice though: but certainly better than using !important and IDs. It stands as a lesser evil. Manage your selectors’ specificity in a smart way and you won’t need to resort to such practices.
Source order
When both importance and specificity are of the same weight, the last resort is the order of which the rules have been declared. In this case, the last one will be applied. As simple as that!
Summary
Using the !important rule is not a good idea if you want to write maintainable code. A better way is to increase selector specificity. Notice that a selector containing 1 ID is more specific than one with 1000 classes and that is the reason why I advise against using IDs. You also need to remember also that a source order plays a role here as well, that’s why it is a good idea to put your stylesheet after any 3rd-party styles. Keeping all those rules in mind will help you write clean and maintainable code that will be easy to modify later.