First time visitor? The tutorials start here.

The Cascade in CSS: Tags, classes, pseudoclasses, etc.

Which takes precedence?

  • tag
  • .class
  • tag.class
  • tag:pseudoclass
  • tag.class:pseudoclass

What if you add ids into the mix?

It can seem confusing when you start adding all these little details to the rules of CSS precedence, but you should always keep in mind that the more specifically-targeted elements will always take precedence over the more generically(or generally)-targeted ones. By the time you finish reading this tutorial, you should have a better grasp on things.

a { color: #f00; }

The above CSS will generically define all anchor links (the <a> tag) to have red text, whether they have been visited or not, whether they are being hovered on or not, and whether you have just clicked on them or not. But once you target “pseudoclasses” of the <a> tag, these pseudoclasses will take precedence over (override) the generic a.

a:visited { color: #008; }

Now if a link has been visited, that link will be dark blue, while any link that has not been visited will still be red.

:visited is a “pseudoclass” of the <a> element, and describes the link’s state. :hover describes the state of hovering one’s cursor over it, :active describes one that has just been clicked on, and :link describes one that has not been visited, is not being hovered on, and has not been clicked on.

It is a good practice to make non-visited links one color and visited links another color, so people will know where they’ve already been. To add more flavor to the page, you can change its color (and other properties aka attributes) when the link is hovered on, and/or when it’s active.

As long as you are defining the pseudoclass for each link state, precedence will then be determined first by whether the pseudoclass describes the link state, then by the order in which it’s listed in your stylesheet, as described in part one of this Cascade in CSS series.

With links, it’s important to list their pseudoclasses in the right order…

a:link { ... }
a:visited { ... }
a:hover { ... }
a:active { ... }

Here’s the logic behind that order…

  • If the link has not been visited, then style according to a:link.
  • If the link has been visited, then style according to a:visited.
  • If the link is being hovered on, override the styling for a:link and a:visited with the new a:hover styling definitions. If there are attributes of a:link or a:visited that are not redefined by a:hover, then it will inherit those particular attributes from a:link or a:visited, accordingly.
  • If the link is active, override the styling in a:link, a:visited, and a:hover with the new a:active styling definitions. If there are attributes of a:link, a:visited, or a:hover that are not redefined by a:active, then it will inherit those particular attributes from a:link, a:visited, or a:hover, accordingly.

You could actually switch a:hover and a:active around, if you would prefer to have active links change attributes when they are hovered on.

Same class, different tag

It is conceivable that someone may want to use the same class name in paragraphs, spans, or even in anchor links, as you can see in the following xHTML examples:

<p class="highlight">Attention: Blah blah blah</p>

<p><span class="highlight">Note:</span> Blah blah blah</p>

<p>Visit <a class="highlight" href=""></a>.</p>

Here, we have a paragraph, a span, and an anchor link, all with the same class. Let’s say we want to make everything in that class bold:

.highlight { font-weight: bold; }

Ok, done. Now let’s say we want only paragraphs with that class to have a border. To make it a little nicer, we might also add some padding, so the text doesn’t butt right up against the border.

p.highlight { border: 1px solid #ccc; padding: 0.25em; }

Now, everything with the class of "highlight" has bold text, while only paragraphs with that class have a border and padding.

Now let’s say you want highlighted links to have a different color than other links, in their various link states:

a.highlight:link { color: #c0c; }
a.highlight:visited { color: #808; }
a.highlight:hover { color: #000; }
a.highlight:active { color: #f00; }

Now you have defined them more specifically than not just .highlight, but also more specifically than a:link, a:visited, a:hover, and a:active. So, any anchor links (<a>) with the class name of "highlight" will take on these new styling definitions, regardless of whether you had defined a different color for .highlight or the various link states of the overall page.

#id .class tagname

This is where it really gets interesting. Let’s say you have this in your xHTML:

<div id="content">
    <div class="box">
        <p class="first">A paragraph here</p>
        <p>Another paragraph here</p>
        <p>A third paragraph here</p>
    </div><!-- end box -->
    <div class="box">
        <p class="first">A paragraph here</p>
        <p>Another paragraph here</p>
        <p>A third paragraph here</p>
    </div><!-- end box -->
</div><!-- end content -->

<div id="sidebar">
    <div class="box">
        <p class="first-p">A paragraph here</p>
        <p>Another paragraph here</p>
        <p>A third paragraph here</p>
    </div><!-- end box -->
    <div class="box">
        <p class="first-p">A paragraph here</p>
        <p>Another paragraph here</p>
        <p>A third paragraph here</p>
    </div><!-- end box -->
</div><!-- end sidebar -->

Now let’s say you want most paragraphs in #content to have a 2em top and bottom margin, but most paragraphs in #sidebar to have a 1.5em top and bottom margin.

#content p { margin: 2em 0; }
#sidebar p { margin: 1.5em 0; }

Ok, so far so good. But you don’t want the first paragraph in each of your sidebar boxes to have such a large top margin, so you want to zero in on those paragraphs specifically and redefine those margins.

You try this, but it doesn’t work:

.first-p { margin-top: 0; }

Why? Because you have already used an id (#sidebar) to target paragraphs in the sidebar (#sidebar p), which will automatically take precedence over the class name (.first-p). In order to make this work, you’ll need to target the first-p class more specifically, using the same id, like so:

#sidebar .first-p { margin-top: 0; }

For this reason, you might as well use the same class-name for the first paragraph in both your content and sidebar areas (using “first” in both instead of “first” in one and “first-p” in the other), rather than trying to come up with new class names that mean basically the same thing.

In Summary

With these rules in mind, it can help to target things as generically as possible, getting more specific only when necessary. Far too often, I have seen people target elements more specifically than necessary in their CSS, which only adds to the size of the CSS file without any real benefit.

If you need clarification on any of this, don’t be afraid to ask in the comments below. 🙂

If you found this article useful, please spread the word:
Stumble it! Digg! Tweet it!

Questions or comments?

Please log in to post a comment. Sorry, but it prevents this from happening. If you're not registered yet, you can register here.