ABSTRACT
In the last posting, I ended with a note that outlined the four ways to determine specificity:
- Create a basic mathematical-style formula.
- Succumb to The Dark Side, and develop Sith powers.
- Burn incense, shake ju-ju sticks and hope the Gods are smiling.
- Fly by the well-educated and experienced seat of your pants.
In this posting, I’ll cover the first method.
Just a warning: If you are someone who has seen real math and algorithms in action, this may seem silly. If you are the “artsy” type, who likes to avoid things that smell like math, then you won’t like this. However, this is an excellent technique for determining an exact level of specificity. It’s not “junk science.” It works.
THE BASICS
I’d link to other sites, but, you know, it’s rather silly. They all seem to want to squabble with each other. The only one that I like is Andy Clarke’s site, and that’s because he brings such a great attitude to it. His explanation is a wee bit light on details, but pretty useful, nonetheless. I think that most of you would prefer using his method over the one I’ll outline on this page.
For the record, this is the official word on calculating specificity. It was written by the folks who wrote the standard. It’s muddy and obtuse, hard to read, but 100% accurate.
Here’s MY Take on the Matter
First of all, I like to take into account cascaded specificity (what I referred to as specificity level 1 -inherited from enclosing elements). This isn’t usually accounted for in other people’s calculations. It’s very weak, and usually not an issue, but it does play a part, and I have been dinged by not taking it into account.
I also ignore inline styles. Besides not being the “proper” way to do it, they trump everything else. Declaring an inline style is the nuclear option.
Okay, I now assign an “exponent” to the specificity levels:
- cascaded Specificity from an enclosing element is Just Plain 1 (Exponent 0) (NOTE: CSS pseudo-classes add 1 to this lowest value (for example: a:visited, or a:hover). This is how a hover pseudo-class can override the base rule. I don’t use pseudo-classes that often, because of very inconsistent browser support.)
- Element Name Specificity is Exponent 1 (10, 20, 30, etc.)
- Class Attribute Specificity is Exponent 2 (100, 200, 300, etc.)
- ID Attribute Specificity is Exponent 3 (1000, 2000, 3000, etc.)
There will be two places that you need to calculate specificity:
- In the element that will be affected.
- In the rule selector.
The first is the specificity that must be exceeded in order for a property to become effective, and the second is the specificity applied to the rule’s properties. Remember that specificity is actually something that is applied to CSS properties, not rules, and that every element has CSS properties applied to it.
The specificity is fairly easy to calculate for rule selectors, not so simple for elements.
Into Action
Okay, time to get the show on the road. I’ve outlined the various levels of “exponents” we’ll use to calculate the specificity of our rules (not elements). The way it works is we count the number of times various levels of specificity are represented in our rule selector, and multiply our exponent for that level by the number of occurrences. Here’s an example:
Let’s say that this is our rule (shudder):
div .some_class p span.another_class em#this_em { font-weight:lighter;font-style:italic }
Here is some markup for the above:
<div class="enclosing"> <div class="some_class" id="a_div"> <p> This is <span class="another_class"><em id="this_em">italicized</em></span> text. </p> </div> </div>
We’ll start with the lower specificities.
Count all the general element names:
div .some_class p span.another_class em#this_em { font-weight:lighter;font-style:italic }
There are 4 of them. Multiply them by the “Element Name Specificity Exponent,” which is 1 (or “10”), and you get:
40
Next, we count the class names:
div .some_class p span.another_class em#this_em { font-weight:lighter;font-style:italic }
There are 2 of these. Multiply them by the “Class Name Specificity Exponent,” which is 2 (or “100”), and you get:
200
Finally, we’ll go to the element IDs:
div .some_class p span.another_class em#this_em { font-weight:lighter;font-style:italic }
There is only 1 of these. We multiply this by the “Element ID Specificity Exponent,” which is 3 (or “1000”), and we get:
1000
The “quick and dirty” way to get the specificity is to add them together:
1240
In order to overrule either of the properties in this rule, another rule needs to have a greater specificity, or have the exact same specificity and be declared after this rule.
We can say that the <em> element with an ID of “this_em” has two CSS properties applied to it:
“font-weight:lighter
“, at specificity level 1240, and “font-style:italic
“, at specificity level 1240.
Let’s add another rule to the mix:
div .some_class p span.another_class em#this_em { font-weight:bold } div .some_class p span.another_class em#this_em { font-weight:lighter;font-style:italic }
We want to make the text bold, as well as italic. That means that we need to override the “font-weight:lighter
” property of the element.
Again, we’ll calculate the specificity for this:
Count all the general element names:
div .some_class p span.another_class em#this_em { font-weight:bold }
There are 4 of them. Multiply them by the “Element Name Specificity Exponent,” which is 1 (or “10”), and you get:
40
Next, we count the class names:
div .some_class p span.another_class em#this_em { font-weight:bold }
There are 2 of these. Multiply them by the “Class Name Specificity Exponent,” which is 2 (or “100”), and you get:
200
Finally, we’ll go to the element IDs:
div .some_class p span.another_class em#this_em { font-weight:bold }
There is only 1 of these. We multiply this by the “Element ID Specificity Exponent,” which is 3 (or “1000”), and we get:
1000
We add them together:
1240
Now, do we think that this will work? We have another rule with exactly the same specificity.
Nope. Can you see why?
The specificity values are exactly the same, but the new rule is declared before the old one. Let’s change the order:
div .some_class p span.another_class em#this_em { font-weight:lighter;font-style:italic } div .some_class p span.another_class em#this_em { font-weight:bold }
Now it works.
Here’s another way to trump the font-weight:
div.enclosing .some_class p span.another_class em#this_em { font-weight:bold } div .some_class p span.another_class em#this_em { font-weight:lighter;font-style:italic }
This increased the specificity of the rule to 1340.
This also works:
body div .some_class p span.another_class em#this_em { font-weight:bold } div .some_class p span.another_class em#this_em { font-weight:lighter;font-style:italic }
This increases the specificity to 1250.
Again, this applies to the rule selector. There’s no simple way to do this for an element. What you need to do is go over the rules carefully, and figure it out, or do what I do: inspect the element with your browser’s element inspector, and see where the errant style properties are coming from, or see what level of specificity needs to be overcome to apply a new style.
A “Gotcha”
In these examples, I made the <em> element’s rule specify a property of “font-style:italic
“. In reality, this is unnecessary. Most browsers render <em> elements as italic anyway (this is an inline element with “baggage”). The following will work just as well:
div .some_class p span.another_class em#this_em { font-weight:lighter }
Note that I removed the “font-style:italic
“.
Remember that I like to take into account cascaded and inherent properties. In the case of the <em> element, the “font-style:italic
” property is inherent.
Inherent always beats cascaded, but nothing else. It is the same specificity level of cascaded, but acts as if it was declared afterwards, so it overrides the prior declaration. For example:
div.enclosing { font-style:normal } div .some_class p span.another_class em#this_em { font-weight:lighter }
Will not override the italic representation inherent in an <em> element.
See for yourself:
The reason for this is that the “font-style:italic
” declared in the enclosing <div> is only at specificity level 1 when it gets to the <em> element. The element’s inherent italic style overrides it.
We can fairly easily override the italic style like so:
em { font-style:normal } div .some_class p span.another_class em#this_em { font-weight:lighter }
This applies a specificity level of 10 to the element, which overrides its inherent specificity level 1 property.
The biggest place that this tends to affect people is in the styling of anchor elements (<a> elements). These have an inherent style that is usually “color:blue;text-decoration:underline”. There are some other things, called “pseudo classes” that also affect many elements (especially anchor elements), but that is a topic for another posting.
The !Important Rule
The !Important rule is a way of coercing a CSS rule to trump even the highest level of specificity and inline styles.
Let’s look at how this works. We’ll start with an example in which the font-weight property of the <em> element is overloaded with very great specificity:
<html> <head> <title>Example 57</title> <style type="text/css"> em { font-weight: normal } body#body_id div#enclosing_id div#some_id p#some_p_id span#span_id em#this_em { font-weight:bold } </style> </head> <body id="body_id"> <div id="enclosing_id"> <div id="some_id"> <p id="some_p_id"> This is <span id="span_id"><em id="this_em">italicized</em></span> text. </p> </div> </div> </body> </html>
Using our calculations, we see that the bold font-weight property value is applied with considerable vigor. It has a specificity value of 6060. The normal weight is applied at a value of only 10.
However, look what happens if we apply the !important rule to the normal weight:
<html> <head> <title>Example 58</title> <style type="text/css"> em { font-weight: normal !important } body#body_id div#enclosing_id div#some_id p#some_p_id span#span_id em#this_em { font-weight:bold } </style> </head> <body id="body_id"> <div id="enclosing_id"> <div id="some_id"> <p id="some_p_id"> This is <span id="span_id"><em id="this_em">italicized</em></span> text. </p> </div> </div> </body> </html>
We see that this trumps even the very specific declaration. This will even override an inline style:
<html> <head> <title>Example 59</title> <style type="text/css"> em { font-weight: normal !important } body#body_id div#enclosing_id div#some_id p#some_p_id span#span_id em#this_em { font-weight:bold } </style> </head> <body id="body_id"> <div id="enclosing_id"> <div id="some_id"> <p id="some_p_id"> This is <span id="span_id"><em id="this_em" style="font-weight:bold">italicized</em></span> text. </p> </div> </div> </body> </html>
This means that you need to be very careful when using the !important rule, as it makes the property value virtually impossible to override. The only thing that is more specific than !important is another !important, applied to a rule of the exact same (or higher) specificity of the original rule.
This example allows bold to override the !important rule, as the new rule is after the original, and is of the same specificity:
<html> <head> <title>Example 60</title> <style type="text/css"> em { font-weight: normal !important } em { font-weight: bold !important } body#body_id div#enclosing_id div#some_id p#some_p_id span#span_id em#this_em { font-weight:bold } </style> </head> <body id="body_id"> <div id="enclosing_id"> <div id="some_id"> <p id="some_p_id"> This is <span id="span_id"><em id="this_em">italicized</em></span> text. </p> </div> </div> </body> </html>
This one does as well, because the !important is applied to a rule with a higher specificity:
<html> <head> <title>Example 61</title> <style type="text/css"> em#this_em { font-weight: bold !important } em { font-weight: normal !important } body#body_id div#enclosing_id div#some_id p#some_p_id span#span_id em#this_em { font-weight:bold } </style> </head> <body id="body_id"> <div id="enclosing_id"> <div id="some_id"> <p id="some_p_id"> This is <span id="span_id"><em id="this_em">italicized</em></span> text. </p> </div> </div> </body> </html>
Is It Worth It?
How much time should we spend carefully calculating the specificity of each of our style rules? We can easily take this too far, and spend ages making sure that we know exactly how specific each rule is, but that can take a very long time, especially if you are modifying a CMS. A CMS will usually have dozens of styles in its theme; sometimes, with rather careless specificity.
The time to be exact is if you are writing code that is meant to be overloaded by others. In this case, you want to use the lowest specificity possible. I try to be careful of this in all code I write, but it is quite possible to get too anal-retentive about this stuff. If you examine the additional CSS for this site, you will see a number of !important rules. Sometimes, the fox just ain’t worth the chase. Use your judgment.
CONCLUSION
This concludes (whew!) my lecture series on the three basic foundations of CSS-based design:
- The concept of separation of presentation from structure
- The two main CSS display modes: block and inline
- The concept of CSS specificity
With these, we are well on our way.
This just scratches the surface of CSS-based design. I’ll cover more as time allows, but this is a good start. I sincerely hope that this has helped to give an understanding of the important basics of using CSS properly.