Specifically speaking.

Specificity - say that five times fast. If, like me, you've used a content management system, you have run into some serious headaches applying css to deeply nested elements. This is not unique to CMSs though. Even if you have complete control over your HTML structure you'll still need to have a couple of tricks up your sleeve to style your pages.

For this post I'm going to take a look at:

  1. Inheritance - sometimes styles are inherited by child elements and we probably need to know how this works, so we're not surprised when all our text turns red.
  2. Specificity - we can decide whether to apply a style globally or to smaller groupings or even individual elements.

To keep this simple I'm going to take a slice of HTML rather than an entire document. Here's our markup, with a couple of classes and ids tossed in.

<div id="main">
    <p class="primary">Spaceships are pretty cool.</p>
    <div>
        <div id="spacehip_1" class="spaceships">
            <h3>Copernicus</h3>
            <p class="primary">The Copernicus is an exo-atmospheric vessel.</p>
            <p>It orbits the sun collecting the energy from solar flares in large batteries.</p>
            <p>These reserves are then sold to energy deprived, colonised planets in the outer solar system.</p>
            <ul>
                <li>Age: 55 years</li>
                <li>Capacity: 6,000 Zettawatt</li>
                <li class="red" id="pink">ZettaSolar Corporation</li>
            </ul>
        </div>
    <div>
</div>

Play along on CodePen

Inheritance

Just like children can inherit property from their parents, CSS child elements can inherit style properties from their parent elements. Easy, right? Here's the tricky part - some CSS properties are inherited, and others are not. Luckily, I found a StackOverflow comment which contains a nice list of the properties that are inherited.

Practically speaking, how does that work? Let's change the font family of the #main div and all its children:

#main {
    font-family: Tahoma;
}

All the text inside the #main div, including the p and li tag text, changed to Tahoma. That was easy. As far as inheritance goes, that covers it. One last thing, it's good to know that inheritance stops where it starts. If the font-family for body is Times and article is Tahoma all the text in my document will be Times, and every element inside my article container will be Tahoma. Note though that inputs and textareas do not seem to inherit any font properties and need to be specifically declared.

Specificity

That's all well and dandy; my text is inheriting the Tahoma font from .main and the color 'black' from body's defaults. Now I want to change my p colors. All my paragraphs should be dark grey, except for those in the .spaceships div - I want them to be an emerald green. There are a couple of ways to do this. Let's take a look.

#main {
  font-family: Tahoma;
}
/* color for all paragraphs */
p { color: #808080; }

/* the many ways to specify color for .spaceships p's. Comment all of these and uncomment them one at a time to see it in action*/

/* target all p's with at least two divs in their ancestry - least specific */
div div p { color: #006400; }

/* target all p's following an h3 tag - it works in this example, but could cause conflicts if you have h3 outside .spaceships divs */
h3 ~ p { color: #006400; }

/* target all p's with a .spaceships div in their ancestry - more specific */
div.spaceships p { color: #006400; }

/* target all p's with a .spaceships div as ancester with a #main div as ancester - even more specific. */
div#main div.spaceships p { color: #006400; }

I'm running into a problem though; because my style for .spaceships's p's are so specific just adding .primary { color: #000 } does not change the color of the p.primary for those paragraphs. It works for the p directly inside #main though. Let's figure out why.

The following styles affect the p.primary directly following div#main:

p { color: #808080; }
.primary { color: black; }

Since p is completely generic, and .primary is specific the .primary properties are being applied. Let's figure out how we're going to make this work for the p.primary in .spaceships. First, let's find the most specific style. We know from just a moment ago it's most probably going to be div#main div.spaceships p. If you'd like to test it, take the styles above and change the color for each option to blue, yellow, red, pink, and purple. Which one sticks?

/* Spacehips div p specificity test */
div#main div.spaceships p { color: grey; }
div.spaceships p { color: red; }
h3 ~ p { color: yellow; }
div div p { color: blue; }

Purple wins; so, now we know our previous conclusion was correct. We can use the same method to test which one will work for p.primary by adding .primary to all our p's. Based on our previous experiment my guess is that we'll need to use div#main div.spaceships p.primary.

/* Spacehips div p.primary specificity test */
div#main div.spaceships p.primary { color: darkkhaki; }
div.spaceships p.primary { color: darkslategray; }
h3 ~ p.primary { color: chocolate; }
div div p.primary { color: aqua; }

Confirmed. We can conclude that in order to override a very specific style selector we need to get even more specific. For our final test, let's see whether classes or ids are more specific. Our last li element has both a class of red and an id of pink. Let's see which one wins. Since CSS is read from top to bottom we'll put the id first, just to prove a point. Feel free to swop them out if you're doubtful.

#pink { color: #FF1493; }
.red { color: #FF4500; }

Looks like ids beat classes. So, if we're trying to be more specific we'll always have to use the id rather than the class to override other styles. Sometimes, previous styles are applied so specificially that you'll need to string together styles and ids, ex. li#pink.red { color: green; }. Test it, put this style at the top of styles and it should override #pink.

Important

Desperate times call for desperate measures. There are times, very few of them, when we are left with no alternative; we call in the big guns. When it comes to specificity important! is the fusion weapon to end all battles. Use it with care, and only when you've exhausted all other options. I've added .primary { color: blue !important } to the end of the CSS portion of our exercise. Uncomment it and see what happens.

WOAH! It overrides even our most specific rule. Use it with care, because it can have unintended consequences - like spending 4 hours in the early hours of a Monday rushing to prepare your presentation for the 8am meeting with your most important client and your boss; pulling out your hair, because you just cannot get that ridiculous icon to sit center to its container - maybe hard coding an inline left: 10px !important in your JS to solve a small, self-inflicted layout issue was not such a good idea, after all. AAGH!

That should cover the basics. For something a little more involved, check out this specificity post on CSS-Tricks