homepage Welcome to WebmasterWorld Guest from 54.167.179.48
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member
Home / Forums Index / Code, Content, and Presentation / CSS
Forum Library, Charter, Moderators: not2easy

CSS Forum

    
CSS Specificity Calculation
A Small Excerpt That Some May Find Useful
cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3631461 posted 12:19 pm on Apr 21, 2008 (gmt 0)

META Note: This is a small excerpt from a series that I'm writing up in a blog, so please understand that it will be incomplete. I just thought that it might be useful.
--
The "Scientific" Way to Calculate Specificity
In the last posting, I ended with a note that outlined the four ways to determine specificity:
  1. Create a basic mathematical-style formula.
  2. Succumb to The Dark Side, and develop Sith powers [stuffandnonsense.co.uk].
  3. Burn incense, shake ju-ju sticks and hope the Gods are smiling.
  4. 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.

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 [stuffandnonsense.co.uk], 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 [w3.org]. It was written by the folks who wrote the standard. Think of it as "going back to the BT." 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 inherited specificity (what I referred to as specificity level 1). 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.

As a general rule of thumb, I always use the lowest specificity possible in any given situation. This is critical if you are writing code that might be modified by others. The lower the specificity, the more easily it can be "stepped on" by subsequent styles.

Okay, I now assign an "exponent" to the specificity levels:

  1. Inherited Specificity from an enclosing element is Just Plain 1 (Exponent 0)
  2. Element Name Specificity is Exponent 1 (10, 20, 30, etc.)
  3. Class Attribute Specificity is Exponent 2 (100, 200, 300, etc.)
  4. ID Attribute Specificity is Exponent 3 (1000, 2000, 3000, etc.)

There will be two places that you need to calculate specificity:

  1. In the element that will be affected.
  2. 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.

This is a good time to throw another monkey wrench into the works. Certain elements have inherent (not inherited) properties. If you noticed, some of the text in example 48 was separated from the text above and below. This is because that text was in <p> elements, and paragraphs have inherent top and bottom margins to them. The specificity of these properties is also at the specificity exponent of 0. This was why I chose the <div> element as an exemplar of a block element. <p> elements are also block elements, but come with a bit of "baggage."

The specificity is fairly easy to calculate for rule selectors, not so simple for elements.

Let me take the opportunity to introduce you to an interesting online tool: a specificity calculator. Paste your code into the text box, and it will catalog the specificity of the elements of your code. To be honest, I'm not that enamored of it. I much prefer using my brain, eyeballs and Firebug. Firebug is just so goddamn kewl that I can't give it enough praise.

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 Firebug, 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.

The simple "add them together" method will work fine, until you have counts over 9 for any of the parts of the formula. In this case, you can express the specificity like this, instead:
10000,200,50,0
You can also remove the "exponents," as you don't need them anymore:
10,2,5,0
ANY number in a left-hand group beats ANY number to its right. For example:
1,2,5,9
The "1" beats everything else.

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 inherited and inherent properties. In the case of the <em> element, the font-style:italic property is inherent.

Inherent always beats inherited, but nothing else. It is the same specificity level of inherited, 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 (like this site does). 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 this site's CSS, 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:

  1. The concept of separation of presentation from structure
  2. The two main CSS display modes: block and inline
  3. 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.

 

sgietz

5+ Year Member



 
Msg#: 3631461 posted 12:48 pm on Apr 21, 2008 (gmt 0)

Yikes!

Dude, it's Monday morning. How could you do this to us?

:D

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3631461 posted 1:09 pm on Apr 21, 2008 (gmt 0)

Sorry. That's actually a common reaction to this kind of thing, and is why Andy Clarke did that Specificity Wars thingy.

swa66

WebmasterWorld Senior Member swa66 us a WebmasterWorld Top Contributor of All Time 10+ Year Member



 
Msg#: 3631461 posted 1:12 pm on Apr 21, 2008 (gmt 0)

Thanks, very well done.

I'm wondering just how well (if at all) the currently in active use browsers truly support this as defined in the standards.

Think I've seen one to many !important rule used as a hack to fully trust it's well supported.

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3631461 posted 1:25 pm on Apr 21, 2008 (gmt 0)

Well, the stuff in that posting was tested on a number of fairly modern browsers, and seemed to behave consistently.

I can show you the original context, with linked examples, but I couldn't put all that here. I just spent about 15 minutes setting it up for this format and removing external links, etc.

This is part G, in a series on specificity that started with A, so there's a lot in specificity.

Thanks!

sgietz

5+ Year Member



 
Msg#: 3631461 posted 6:51 pm on Apr 21, 2008 (gmt 0)

OK, Monday morning turned to afternoon, and my brain works better now.

I did some googling and arrived at this, which would make this process much easier. I hope this URL won't get wiped from my post .. here goes:

http://www.rebelinblue.com/specificity.php

[edited by: SuzyUK at 7:29 am (utc) on May 23, 2008]
[edit reason] note: this calculator has limitations [/edit]

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3631461 posted 7:00 pm on Apr 21, 2008 (gmt 0)

That's the critter I linked to (I took the link out the translation I did for this site).

It works, but has issues. I can get a bit "fancy pants" with CSS, and it returns garbage for a lot of my CSS.

Basically, the gist of this (and the previous six parts that preceded it) is that specificity is something we should understand, but that we won't need to go to these lengths to use. I almost never use this method. However, it's necessary in order to debug, sometimes.

Think of it as having to learn a differential equation to perform a Fourier transform, then never having to use it, because you always use FFT. Learning it was not a waste, because you understand the principles. You can solve issues and make design decisions with a better chance for success.

That Option #3 (Ju-Ju sticks) tends to be the preferred method of a large number of Web designers, because they don't actually understand specificity.

SuzyUK

WebmasterWorld Senior Member suzyuk us a WebmasterWorld Top Contributor of All Time 10+ Year Member



 
Msg#: 3631461 posted 8:10 pm on Apr 21, 2008 (gmt 0)

cm.. Nice Post - lots of thought went into that!

Thank you, am reading and digesting because you know specificity is my favourite subject ;)

First of all, I like to take into account inherited specificity (what I referred to as specificity level 1). 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.

that'll be the cascade there is no such thing as inherited specificity, you can override the cascade with basic specificty .. but the basics are the cascade.. which is what cascading stylesheets are named for, so you should not write that bit off :)

[edited by: SuzyUK at 8:11 pm (utc) on April 21, 2008]

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3631461 posted 8:13 pm on Apr 21, 2008 (gmt 0)

that'll be the cascade there is no such thing as inherited specificity, you can override the cascade with basic specificty .. but the basics are the cascade.. which is what cascading stylesheets are named for, so you should not write that bit off!

Thanks!

I'll update my postings when I get the chance. Proper terminology is very important, especially these days, with Google and all.

Is there a more official name for inherent properties?

SuzyUK

WebmasterWorld Senior Member suzyuk us a WebmasterWorld Top Contributor of All Time 10+ Year Member



 
Msg#: 3631461 posted 8:15 pm on Apr 23, 2008 (gmt 0)

they're just known as inheritable properties Chris afaik

specificity or getting specific is as you say only important if trying to override css which you don't have access to. (or at the very least understanding why LVHFA is the preferred order for links). The !important override is, IMHO, like taking a mallet to the job, it's an accessibility feature and should not be abused. It's only going to lead to compounded problems down the line if you use it your stylesheets now. It's a stop gap but should never be necessary.

I understand what you're saying about overriding CMS templates but again if it's your template it should be recoded accordingly.. imagine if the CMS theme builder built !importants into their theme :o (I know because I'm fighting with yet another Drupal Theme at the minute!)

----------
Now that I've had time to properly read your post I see the basic flaw that is likely to strike first whenever someone would come across a specificity issue (even Andy Clarke didn't get it right in his wonderfully amusing Sith Power post)

CSS Specificity is NOT calculated in base10

I know you've referred to this in your post already, but honestly it's important.. the calculator that sgietz links to and you refer to (I've put link back for this post only) also suffers the same malady. You can brush it off with the "need more than 9 parts" but with the adjacent sibling selector support these days that's not an improbability?

so (OK I was prodded! by.. you know who you are ;)) I reworked the specificity calculator now it reflects the infinite base that Eric Meyer refers to in his post and the specs also (but as usual are not patently clear about!)

It's still very likely that people will count in base10 and that's OK as most times that's enough but you know it's not quite right and so do I.

e.g. this code:
.mytable td {color: blue;}
html body table tbody tr td+td+td+td+td+td {color: red;}

would return '11' for both elements under your method and the original calculator, effectively suggesting that the color would be red because the second rule should apply by merit of the cascade..

..however it should be 0,0,1,1 and 0,0,0,11 respectively - so despite its eleven elements the second rule is still "trumped" by the first because the one in column 'c' for the first rule beats the 0 in column c for the second despite the number in column 'd'

notation for specificity is a, b, c, d

-----------------------------

it's always been a hard subject to tackle, and I can't link anywhere but my own beta yet so here's an attempt at a rewritten CSS Specificity Calculator [suzyit.com].

I haven't tried to explain the how or why but I suppose to follow the "Malarkey" ;) what we we need is a visual hierarchy where 1 x Emperor (a) can wipe out any amount of Vaders (b)?

-Suzy

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3631461 posted 1:08 am on Apr 29, 2008 (gmt 0)

Suzy,

Sorry I forgot to post this earlier.

Your specificity calculator is really nice. Thanks so much. I can mention it in my pontifications if you want, but I'm not sure if you want extra links to it until you have it hammered out.

SuzyUK

WebmasterWorld Senior Member suzyuk us a WebmasterWorld Top Contributor of All Time 10+ Year Member



 
Msg#: 3631461 posted 9:26 am on May 23, 2008 (gmt 0)

Chris, feel free thanks..

That link is its permanent home, I've also now hammered out some details:

rebelinblues calculator couldn't differentiate between .span and <span> or any classes/ID's that had the same name as an HTML elements, Stephen let me know this so this should now be fixed.

It now counts XML elements (except if they've a full stop/period in their actual name, while although legal, is considered bad practice?) - I don't think there's anything I can do about that as there is no way to tell if
hello.world is element.class or simply an element. Hyphens underscores digits etc are OK I think.

You can maybe help I haven't allowed for the :colon which again although a legal character in an XML element is recommended not for usage as it's reserved, is that right?

Updated to reflect CSS3 properties, especially the negation selector, specificity calculations count the selectors inside the brackets but not the negation itself.

Anything else? what about the pipe character which denotes the namespace, does the element before the pipe count towards specificity?

Would appreciate some fresh eyes on it to test a few weird/wonderful combinations as I can no longer see the wood for the trees :)

-Suzy

[edited by: SuzyUK at 10:14 am (utc) on May 23, 2008]

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3631461 posted 3:15 pm on May 23, 2008 (gmt 0)

Oh, I see what you mean.

Yeah, the rules should really be set forth by the W3C. I'm not aware of how we bring up these "edge" situations for some clarification. Maybe there's something on Eric Meyer's Site [meyerweb.com] (You can't get much more authoritative than him).

Thanks for the code. I may mess around with it when I get the chance. I have a lot of irons on the fire right now.

SuzyUK

WebmasterWorld Senior Member suzyuk us a WebmasterWorld Top Contributor of All Time 10+ Year Member



 
Msg#: 3631461 posted 4:53 pm on May 23, 2008 (gmt 0)

think it's finished for now, just got some help in PHP which helped me tidy one part and also helped me spot another potential error if there had been multiple (nth-xx) selectors in a rule..

not too worried about the pipe separator, it's hardly a pressing issue for now and it can be very easily fixed when I know what to do with it ;)

Thanks for the code. I may mess around with it when I get the chance

Please do, and you, anyone let me know if you think it can be improved - though it's fairly short already and uses very simple clean and count logic - I'm not sure that there's much demand for it as the simple visual count is enough for most needs I would think.

But Chris, as you are into XML I thought you could help with coding practices for element names, I know what the specs say and that's what I've coded to, but I read on somewhere possibly o'reilly or a working group mailing list that usage of dots and colons within the names is considered bad coding practice.. if so it means the one wee flaw is likely not to be an issue. Of course it's not likely an issue as I don't know of anyone who would use it, I count visual too though it possibly might help if you can't instantly remember the difference between a pseudo class and a pseudo element! (that'll be me then :))

Oh well enjoy it if you need it, it's helped me with my PHP and regex's :)

-Suzy

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3631461 posted 5:11 pm on May 23, 2008 (gmt 0)

The PHP is remarkably simple. I was quite surprised.

Yeah, the thing about XML is that it is a flexible substrate, and it's up to the implementation to specify constraints. The thing about colons and periods should really be laid out in the XHTML DTD [w3.org]. I'm not sure if a DTD can get that fine-grained. I'm pretty sure a schema can. httpwebwitch [webmasterworld.com] might know. He's even geekier than I am on XML.

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / CSS
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved