You are currently looking at an older section of the wincent.dev website.
Please check the new version of the site at https://wincent.dev/ for updated content.

wincent knowledge base

Main | Localization on Mac OS X »

November 10, 2004

Cleaner HTML using CSS

CSS, or Cascading Style Sheets, have been around for a while now, but I don't think I've ever truly "gotten" them, until this week that is... Years ago, back in the days of Netscape Navigator 4, I had a brief play with them. They promised to deliver a greater degree of control over the final appearance of the page. In fact, many even argued that you could throw out tables and use CSS to do layout (examples here and here).

The trouble was, one company in particular didn't support CSS very well, requiring all sorts of hacks to get it to display correctly. This seemed like a travesty in the 21st century with Mozilla and others championing the cause of standards-compliance. It seemed that the ugly hacks required to get CSS to work on all browsers were not much better than the complicated nested tables that they replaced. Over the years I've periodically checked back to see what the state of play was in the realm of CSS. In general it was something that I tacked on to my pages where I thought it wouldn't break things, but it didn't really revolutionize the way I went about designing my pages.

All that seems to be changing. Thanks to Safari and it's WebKit engine (also used in OmniWeb), and the host of browsers using the Mozilla Gecko engine (such as Camino, FireFox and of course Mozilla itself), I can now write standards-compliant web pages and be confident that around 99% of my intended audience will see them as I intended them to be seen. Opera also does a great job of compliance, and even Microsoft's browsers tend to display simple pages more or less correctly, even if they don't end up fully supporting every little touch and feature that you've added.

I'm a Mac software developer, which puts me in a very special position. I know that most of my visitors will be using Macs, and they'll see what they should be seeing. Those who visit using Windows machines will see something reasonably close, because my pages are fairly clean and simple.

It's a great time to be a web designer.

With that lengthy preamble out the way, the rest of this article will talk about what I think is the real strength of well-prepared CSS: it's ability to help you write clean HTML.

How to use (and not use) CSS

It's only in these last few days that I've finally "gotten" CSS. It's just like Object-Oriented Programming (OOP), in a way. In OOP, you minimize redundancy and maximize code re-use by moving common elements "up" the hierarchy. With CSS, you do the same: you move common styling information "up" (from the HTML into CSS styles), and in fact you can even move it right out into a separate file. That's what I've done with the current design for wincent.dev; there's only one style sheet on the whole website, and every other page makes use of it.

There's a clear advantage there in terms of style re-use. Change that one style sheet and everything else gets updated automatically.

But it wasn't until I read this excellent tutorial on CSS selectors by Max Design that I realized there was another benefit that I hadn't seen before. I suddenly realized how much cleaner my HTML could become if I just started using selectors wisely. Use selectors wisely and you'll not only move more styling information "up" and out of your HTML, but you'll get the corollary benefit that your HTML source is infinitely more readable and better looking.

The key thing to bear in mind is this: Override existing HTML elements to produce the look you want.

You can also think of this conversely, as: Don't write special classes for each and every type of element.

Applied judiciously, these two little ideas will help you to write shorter, more compact style sheets, and much better looking HTML. Let's demonstrate this by looking at an example of what not to do. Imagine a web page that has the following content:

<div id="container">
  <p class="subheading">Acknowledgements</p>
  <p class="body-paragraph">Thanks to everybody at WorkCo, my family, and my lovely children.</p>
</div>

Imagine that it also has some other content in a sidebar:

<div id="sidebar">
  <p class="sidebar-subheading">Links</p>
  <p class="link-group-heading">Webmail providers</p>
  <ul class="sidebar-link-list">
    <li class="sidebar-link-list-item"><a href="http://mac.com/">mac.com</a></li>
  </ul>
</div>

This is an atrocious example of CSS gone wrong. You can imagine the entire site peppered with hundreds of different styles, and the accompanying, gargantuan, style sheet. It's true that the author has moved lots of HTML attributes out of the HTML, but it's been only to replace them with a myriad of CSS class names. All of this looks very difficult to maintain; the class names are hard to remember and easy to misspell. There are too many of them.

With intelligent use of selectors the same examples could be written like this:

<div id="container">
  <h3>Acknowledgements</h3>
  <p>Thanks to everybody at WorkCo, my family, and my lovely children.</p>
</div>
<div id="sidebar">
  <h3>Links</h3>
  <h4>Webmail providers</h4>
  <ul>
    <li><a href="http://mac.com/">mac.com</a></li>
  </ul>
</div>

Notice how the result is much cleaner. The only CSS visible now are the two ids, "container" and "sidebar". The use of standard HTML elements like <h3> means that even in ancient browsers which don't support CSS, the logical structure of the page will at least be visible, even if the exact appearance is not. The example in question is very short, but if you imagine it applied to a page with a complicated structure or lots of styles, then the benefits soon become evident.

The key to writing clean HTML like this is to use CSS selectors intelligently. In the example above, we can control the style of the various elements using CSS like the following. I haven't actually shown the style information, but I've indicated the selectors we could define to target the element we wish to control:

#container { /* appearance of things in "container" */ }
#container h3 { /* what do headings look like in "container"? */ }
#container p { /* what do paragraphs look like? */ }
#sidebar { /* appearance of things in "sidebar" */ }
#sidebar h3 { /* major headings in "sidebar" */ }
#sidebar h4 { /* minor headings in "sidebar" */ }
#sidebar ul { /* lists in "sidebar" */ }
#sidebar li { /* list items in "sidebar" */ }

In keeping with what I said about moving things "up" the hierarchy, you can use selectors to define the look of things in higher-level elements of the page, like the "body" element, or something fundamental like the "p" element. By doing this you minimize the amount of repetitious styles you need to define in your style sheet. And you're not forfeiting any control; notice that even though you use the same ("h3") tag in two different places, you can still independently control the appearance of each instance.

Selectors are incredibly powerful things. You're not just limited to saying "class X should look like this", nor even things like in our example above, "element Y should look like this whenever it appears inside Z". You can define targets like "element A should look like this whenever it appears inside a B, which appears inside a C, which appears inside a D", or "element E should look like this whenever it is immediately preceded by element F", or "element G should look like this only when its immediate parent is element H", and so forth. The level of control possible is truly impressive. It's this kind of control that makes the dynamic menus that you see above in the navigation bar possible (see this article by Eric Meyer for a description of the idea that's behind the effect); all of this is down without any JavaScript whatsoever, and it's pretty much guaranteed to work in your browser (you're not using Internet Explorer, are you?...)

Conclusion

The core thing to take from this article is that piece of two-side advice:

  • Override existing HTML elements to produce the look you want.
  • Don't write special classes for each and every type of element.

And do visit the select tutorial referred to above so you can learn about the all the ways in which you can use selectors to write better CSS.

Posted by wincent at November 10, 2004 10:31 AM