CSS is a declarative language: You declare that any elements which match a given CSS selector (the part before the curly braces) should apply the property values inside the rule (the part inside curly braces). But what happens when multiple selectors (and therefore multiple rules) apply to the same element? Or, how do you override styles for a particular element that you do not want? Why not just use !important
to make sure that what we want is being set?
The steps that CSS takes in deciding which properties are chosen are well-defined, if you want to read the CSS specification on cascading, which is how the rules from different stylesheet types get layered and applied, and its companion CSS specification on specificity, which is how a CSS selector is ranked in importance. Since you're not a browser vendor, it might be a bit easier to read on.
When we're developing a web page, which CSS rules override which other CSS rules is made up of two steps:
- Compare the selector specificity, higher specificity wins.
- Compare the position of the rule in the stylesheet, later rules win.
Calculating a selector's specificity is a bit confusing: The selector is broken into parts, the parts are organized into buckets, and the buckets counted to form the specificity. This results in a specificity that looks something like "1,0,0,1" or "0,2,3,0".
There are four buckets that make up specificity:
- IDs (
#id
). - Elements and attributes (
div
,[attr=value]
) - Classes (
.class
) - I don't know
Each part of the selector is put into one of these buckets.
#foo /* 1 ID, 0 elements/attributes, 0 classes, 0 unknown */
#foo.fuzz /* 1 ID, 0 elements/attributes, 1 class, 0 unknown */
.fuzz #foo /* 1 ID, 0 elements/attributes, 1 class, 0 unknown */
#foo div.fuzz /* 1 ID, 1 elements/attributes, 1 class, 0 unknown */
.fizz.buzz /* 0 IDs, 0 elements/attributes, 2 classes, 0 unknown */
Then the buckets are compared one by one to rank the selectors. First the selectors with the most IDs. If the selectors have the same number of IDs, then the selector with the most elements/attributes wins. If they have the same number of elements/attributes, then the selector with the most classes wins.
/* The above selectors, ordered by specificity */
The more specific a selector, the more important the definition, the more powerful the properties inside. So, if we want to override a property set by a single class selector (.fizz
), we can define another class and give our selector two classes (.fizz.buzz
) to increase its specificity.
.fizz { color: red; font-weight: bold }
.fizz.buzz { color: blue }
<div class="fizz">This text is red and bold</div>
<div class="fizz buzz">This text is blue and bold</div>
If two selectors have the same specificity, the one that comes last is the one that wins. So If we tried to override the color above with just one class, it would work depending on which CSS definition came first:
.fizz { color: red; font-weight: bold }
.buzz { color: blue }
<div class="fizz">This text is red and bold</div>
<div class="fizz buzz">This text is blue and bold</div>
.foo { color: blue }
.baz { color: red; font-weight: bold }
<div class="baz">This text is red and bold</div>
<div class="foo baz">This text is still red and bold</div>
This ordering of rules is defined by the order of <link>
and <style>
tags in your markup, which can make for confusing results where re-ordering your external stylesheets causes your design to break!
The best practices to prevent this is, unfortunately, constant vigilance. Keep your base stylesheets on top, and your custom site or page overrides on the bottom. If this isn't good enough, you can always make your custom selectors more specific by adding classes (even to the <body>
tag).
To complicate the relative simplicity of specificity and ordering, you are allowed to mark any property value as important by adding the !important
tag. This was added mostly for users of web browsers to be able to add their own styles to your page, and as such, !important
overrides the regular order of style sheet application (more on that below).
User-Agent stylesheet User stylesheet Document stylesheet