CSS Consistency vs. Payload

November 18, 2009 — Code

Managing stylesheets is a challenge in any web application. If you’ve worked much with object-oriented programming you may be naturally inclined to use OO techniques when designing CSS. This is a good idea, of course, as it leads to more modular and reusable code. However it’s not always straightforward in practice because the size of the code itself (download time) can affect performance. In my experience it is sometimes necessary to sacrifice the benefits of an OO design for speed.

The Consistency Rule

Nicole Sullivan has written eloquently about the use of object-oriented programming concepts in CSS to make your code more efficient and maintainable. She offers many specific recommendations, including the following:

Avoid location-dependent styles.

For example, if you have two second-level headers (<h2>s) that both should be second level headers but need to look different, don’t do this:


<style type="text/css">
  .header h2 { font-size: 125%; color: green; }
  .news   h2 { font-size: 108%; color: blue; }
</style>

<div class="header">
  <h2>...</h2>
</div>
...
<div class="news">
  <h2>...</h2>
  <h2>...</h2>
  <h2>...</h2>
</div>

Instead, do this:


<style type="text/css">
  h2.header { font-size: 125%; color: green; }
  h2.news   { font-size: 108%; color: blue; }
</style>

<div>
  <h2 class="header">...</h2>
</div>
...
<div>
  <h2 class="news">...</h2>
  <h2 class="news">...</h2>
  <h2 class="news">...</h2>
</div>

The reason for this is consistency: if you copy an <h2> from one part of a page and paste it somewhere else, it should look the same. It’s kind of like encapsulation in OOP: elements within a <div> shouldn’t be stylable from outside the <div>, unless they themselves are members of a class which applies style.

Another reason for this rule is that, according to Google, “inefficient” location-based selectors are rendered more slowly by web browsers. Try Google’s PageSpeed plugin for Firebug for more information and to see how your selectors rate.

The Problem

While I agree with most of Nicole Sullivan’s advice, and use an object-oriented approach 80% of the time, I’m a little hesitant about killing all of my location-dependent selectors. Here’s why: In the simple example above, the location-independent approach adds 26 bytes to the size of the HTML. Certainly 26 bytes is nothing to worry about, but what happens on an actual web page where you might need to add class="..." attributes to 50, 100, or 500 tags? Could the size increase become significant?

I asked Nicole about this earlier today at the Web 2.0 Expo and she cited real companies that have significantly reduced their CSS payload (eg: from 60 to 15 KB) by switching to her OOCSS library. However, I question whether a one-time savings of 45 KB (assuming browsers properly cache your stylesheet) justifies an increase of perhaps 20 KB on every page of your site. (With caching configured correctly, a browser will load your stylesheet once, but if a user views 20 pages of a site they will load 20 HTML files, all of which will have grown.)

Let’s say the average HTML class attribute (eg: class="product") is 16 bytes long (a conservative figure, I think). Given a web page which lists 40 products in a table, the CSS with location-dependent will apply style to HTML like this:


<table class="products">
  <tr>
    <td><img src="..." /></td>
    <td><a href="...">Product Name</a></td>
    <td>Description</td>
    <td><span>$9.99</span></td>
  </tr>
  <!-- 39 more rows like this -->
</table>

If we get rid of location-dependent CSS selectors we need to do something like this instead:


<table>
  <tr>
    <td><img class="thumbnail" src="..." /></td>
    <td><a class="product-name" href="...">Product Name</a></td>
    <td>Description</td>
    <td><span class="price">$9.99</span></td>
  </tr>
  <!-- 39 more rows like this -->
</table>

We remove one class attribute from the <table> tag, but we add 3 to each of the 40 rows:

(3 * 40) * 16 bytes = 1920 bytes

We just added almost 2 KB to each product listing page, and will add more if multiple class names are used and more elements need class attributes. Whether the increase is meaningful is outside the scope of this article (watch this presentation by Microsoft and Google) and, to some extent, depends on your application. My point is only that there can be an increase in file size and a corresponding decrease in page performance when you use this technique. The magnitude of the change depends on your particular HTML and how your site is used. If you only expect people to view one page per visit then you probably only care about overall (HTML + CSS) file size, but if users will be viewing many pages, HTML file size may be the more important number. Saving 20 KB in your stylesheet may not make sense if it increases the size of each page by 10 KB.

To be clear: I’m not suggesting that you stop using OO design in stylesheets, or that you start using location-dependent selectors everywhere. Most sites I’ve seen could benefit significantly from better CSS logic, and OOP has many valuable lessons to teach. I’m only saying this: be aware of the side effects of all design patterns, avoid becoming married to any one approach, and choose the right strategy for each problem. There are cases in which C is a more appropriate language than an object-oriented alternative. And there are cases—and this is Nicole Sullivan’s pitch—where the increased file size will be negligible compared with the efficiency and maintainability gained by avoiding naive nested selectors. Be sure to know which case you’re dealing with.


comments powered by Disqus