targeting base variants with css

I'm all for using classes to add extra semantics. Even with stuff like html5 microdata around it's still the easiest and fastest way to make your code comprehensible to both machines (mostly theory though) and other developers working on your html. On the other hand it can put a serious strain on the guy responsible for the css. One particularly annoying problem has always been singling out base variants in css, so here's a quick rundown of the best way to do this.

say, what are base variants?

I guess I'll start by explaining what I consider to be base variants. When using class names for semantical purposes, the first thing to do is come up with a name for a particular component and add that as a class attribute. Usually it doesn't end there though. It is not uncommon that (semantical/visual) variants of one particular component exist, so to mark those variants you have to add a second class to the base class, like so:

.focus {} .focus.news {} .focus.topArticle {}

The css excerpt above illustrates the setup I'm talking about. The focus class is used for whatever piece of content on a page that advertises other content on your site (more about that in a future article), the additional classes describe the nature of the content that can be found in the .focus component. The base variant in this example is .focus.

Not all instances need an extra specifying class, so the base variant will appear wherever the component contains nothing more than generic content. Another possible reason for ending up with a setup like this are last-minute changes. Imagine that you implemented one version of a component all over your project, but right before launch they decide to add a (functional or visual) variant of this component. Rather than add a extra class on all base variants (which is usually a rather large cost on the back-end side), you just add a specifying class on the new variant.

the problem

As long as the additional classes only indicate semantical differences or small visual touch-ups you won't have any trouble with this way of working, but sometimes semantically related components can end up with designs that wildly differ from each other, even when they appear on a single page. Now, if you added all your css styling to the base variant you'll be cursing all the way through when you need to reset half of your styles to match the new design.

Even worse it that every design change of the base variant means you'll need to check the impact on the other, visually unrelated variants. Things get messy real fast and what you end up with is bugs, crap code and annoyed customers.

matching base components

1. div[class="focus"] {} 2. div[class~="focus"] {}

Luckily the attribute selector can help us out here. The first line of code above targets all divs with a single class focus. If you want an alternative for .focus (as we know it in css) you can use the second line. It's a subtle but important difference that helps us to identify base variants. (props go to Jochen Vandendriessche for bringing this to my attention).

Mind that this is not fool-proof though. Browser support is okay (all the way down to ie7 and with a little javascript trickery it's easy enough to duplicate the css on a computed class for ie6) but additional characters (like spaces, tabs, ...) can still mess up your targeting. They should be easy to trim in most cmses but I'm sure there are some exotic cases out there where this could be a major problem. Another issue lies with adding (trivial) extra classes through javascript for whatever reason (think modernizr), which will again mess up your css target.

All of these issues are rather minor though and don't really render this method unusable. Still, be weary that they might still occur, usually when you least expect it.

ignoring a specific component variant

1. div.focus:not([class~="news"]) {}

And while we're at it, here's another little tip. Consider a situation where you have one base variant and 4 other component variants with slight visual touch-ups. Now imagine a fifth one (let's say .focus.news) being added that looks completely different from all the rest. The selector above will help you style all the existing variants while keeping any existing styling away from the .news variant.

conclusion

With ie6 almost out of the picture we can finally start using more powerful css selectors, then again we have to make sure we're fully aware of all the complications towards future-proof coding. The examples above will work quite well in these very specific circumstances, but know that they can easily be overturned by changes later on in the project. Such changes might render your css setup completely obsolete, forcing you to start all over again. As future changes are always difficult to predict better think twice before using these techniques, but they can still come in handy for some quick fixes or in well-defined use cases.

As a final thought, I guess this also illustrates that even though we might have more powerful css selectors available to us now, they're still far from powerful enough to really translate our needs to a matching css selector. At first glance the attribute selector might benefit from logical operators, though that might lead us too far. Or maybe this is just another good argument to stop using classes for semantical purposes. Alternatives are welcomed.