Battling the Chaotic Style Sheet

August 23, 2005

Recently I've been in a battle against large, messy, unwieldy style sheets. I always start out so neatly, organizing my rules by selector and carefully keeping track of them. Then sometime around 3 a.m. one morning, the neatness wears off. I can't remember if I've already written a rule similar to what I need, and frankly I've stopped caring. The heck with it, I grumble, let's just write a new rule and toss it in there.

You can probably guess how well that's been working for me. The resulting style sheet is a tangled heap of rules going every which way. Editing style sheets is the pits, let me tell you.

In an effort to write style sheets I can still figure out the next day, I've been trying some new techniques. In particular, I've been trying to pay greater attention to specificity, inheritance and order. Maybe it doesn't sound like much, but it's really made a difference.

Let me give you an example. Before, I might have had these two rules hiding in different spots in my style sheet:

.outline h2 {
color: #cc0000;
margin-bottom: -18px;
padding: 0;
font: bold 16px/100% 'Trebuchet MS', Trebuchet, Arial, sans-serif;
}

#sidenav h3 {
color: #009000;
margin-bottom: -18px;
padding: 0;
font: bold 16px/100% 'Trebuchet MS', Trebuchet, Arial, sans-serif;
}

By combining these two rules, then following it with a separate rule for color for #sidenav h3, I eliminate an awful lot of repetition:

.outline h2, #sidenav h3 {
color: #cc0000;
margin-bottom: -18px;
padding: 0;
font: bold 16px/100% 'Trebuchet MS', Trebuchet, Arial, sans-serif;
}

#sidenav h3 {
color: #009000;
}

This works because the order of rules is important in CSS--when there are two similar rules, the last one is the rule that's applied. In this case there are two rules for color, but the one for #009000 comes last, so the #sidenav h3 head will be that color (green).

I've been using a few other techniques to try to tighten up and shorten my style sheets, so they're easier to read and make more sense (oh, and are quicker to download, too). This one has to do with specificity and inheritance. Say I want to add a header called #sidenav h3.small that's very similar to the two headers I already have rules for. I want it to have the spacing of the .outline h2 and the color of the #sidenav h3, but I need the font size to be smaller.

.outline h2, #sidenav h3 {
color: #cc0000;
margin-bottom: -18px;
padding: 0;
font: bold 16px/100% 'Trebuchet MS', Trebuchet, Arial, sans-serif;
}

#sidenav h3 {
color: #009000;
}

#sidenav h3.small {
color: #009000;
margin-bottom: -18px;
padding: 0;
font: bold 12px/100% 'Trebuchet MS', Trebuchet, Arial, sans-serif;
}

Rather than writing the whole rule for #sidenav h3.small out like I did above, I can use inheritance to give it the values of the #sidenav h3.

.outline h2, #sidenav h3 {
color: #cc0000;
margin-bottom: -18px;
padding: 0;
font: bold 16px/100% 'Trebuchet MS', Trebuchet, Arial, sans-serif;
}

#sidenav h3 {
color: #009000;
}

#sidenav h3.small {
font: bold 12px/100% 'Trebuchet MS', Trebuchet, Arial, sans-serif;
}

In this case the #sidenav h3.small selector will inherit all the values of the #sidenav h3. In addition, because #sidenav h3.small is more specific than #sidenav h3, I can then give it the correct (smaller) font size. In CSS, the more specific rule is always the one that's applied. So the last font rule (making the size 12px) will take precedence over the 16px font rule.

Using these techniques is easier if you group style rules by selector or element. This can be a pain; sometimes I'll work on a page that has h2 and h3 heads, an unordered list and special text styles. Instead of flipping back and forth in the style sheet to each of those areas, I'll write the rules for all of them in one place, then move the rules to the groups they belong to when I'm done.

One more thing--if this looks confusing, join the club. At first I thought I was creating a bigger mess than I was trying to clear up. But after a little practice, you learn to read down the list of rules, sort of automatically adding and eliminating the properties that belong to each selector. It actually didn't take me too long to get the hang of it, and that's saying something.

If you want to read in more detail (and clarity) about these concepts, here are some great links:

The Cascade

Specificity