Skip to content

CSS performance, who cares?

You probably didn’t notice it, but the way you write CSS affects the rendering speed of the browser. Should you care about that? Most likely not, but it is possible to freeze your web page with inefficient selectors.

Lately I read the following text in Building iPhone Apps with HTML, CSS, and JavaScript (O’Reilly) on using ID’s in CSS:

“There are differences between class and id. Class attributes should be used when you have more than one item on the page with the same class value. Conversely, id values have to be unique to a page.

When I first learned this, I figured I’d just always use class attributes so I wouldn’t have to worry about whether I was duping an id value. However, selecting elements by id is much faster than selecting them by class, so you can hurt your performance by overusing class selectors.”

Huh? I never use ID’s in CSS selectors, but I never experienced slow rendering either. I wanted to test if it’s stupid not to use ID’s.

First I wanted to see if it was even able to create a CSS that was hard to parse. Google has a nice article about writing efficient CSS selectors, so that seemed like a good start before setting up a test. In short there are 2 things that make a fast CSS selector:

  • Make rules as specific as possible
    This means that div.content is faster than *.
    You have to be especially specific with the rightmost selector, since the browser reads CSS selector from right to left.
  • Avoid (large) descendant rules
    An example of a descendant rule is div.content div.column1 div.columnHeader h2. Descendant rules are less efficient than rules with a single selector, like h2.

Test 1: setting up extremely inefficient CSS

The most inefficient selector by far is *. Combined with large descendant rules you get extremely inefficient selectors:

* * * * * * * * * {
	background: #ff1;
}
* * * * {
	background: #ff2;
}
* * * * * * * {
	background: #ff3;
}

I created a CSS file of about 20KB in size with 3600 asterisks characters (*). I combined it with a very large HTML file (1MB) with 9000 opening HTML brackets (<). Because I only wanted to test the CSS rendering, I added the following JavaScript to be able to load the CSS file on my local computer after the page was loaded.

	Load CSS
	

Results Test 1

Browser Render time (sec)
Firefox 3.6 2
IE 8 4
IE 7 6
IE 6 11
Chrome 6 4

All tests were done on my computer (Vista with Intel Duo Core @ 2.4GHz) except for IE7 and IE6. IE7 was tested on a Vista machine with Intel Core Duo SPU @ 2.67Ghz. IE6 was tested on my machine with Virtual PC and on a PC with Windows XP SP3 and a Pentium 3 CPU 3GHz.

The results show that browsers freeze for at least 2 seconds in order to render the CSS. So it is possible to screw up your rendering, but you really have to make an effort for it with large HTML files and unrealistic CSS selectors.

Test 2: setting up a more realistic scenario

In this test I created a more realistic scenario. I took an existing CSS file and altered it until it was 113KB in size and contained about 1050 selectors. I changed the CSS rules until the bulk of the code looked like this:

.Homepage .containerText {
	position: relative;
	margin: 15px auto 0px auto;
	width: 960px;
	background:#ffffff;
}
.Homepage .containerText .containerLeft {
	float:left;
	width:450px;
	padding:10px 20px 45px 10px;
}
.Homepage .containerText .containerLeft p {
	margin:0px 0px 5px 0px;
	color:#414a49;
	line-height:1.286em;
}

So most of the code in the CSS file consisted of descendant selectors with classes and hardly any tag names. The corresponding HTML page was also created from existing code and copy-pasted until the file was 107KB in size with almost 600 opening HTML brackets (<). Now we have a relatively large HTML and CSS, but not unrealistic. Once again I tested it in different browsers:

Results Test 2

Browser Render time (sec)
Firefox 3.6 0
IE 8 0
IE 7 0.5
IE 6 1.5
Chrome 6 0

All modern browsers responded so fast that I couldn’t really notice it needed rendering time. This means that the CSS file does not need any optimization by utilizing ID’s. The only browser that could profit from more efficient CSS selectors is IE 6. But since I don’t have to support IE 6 anymore, it’s not worth my time.

Conclusion

Writing fast CSS certainly will help some browsers on slow PC’s. But that is a minority of the users. So unless you have special requirements for your website, you’ll be better off focusing on writing logical, maintainable code than trying to get the browser to render a few milliseconds faster. There are some considerations though:

Being more specific

A few years ago I switched from writing .foo to writing a.foo. Adding the tag name in the selector gives me a better idea what I’m styling. Now I know that this coding style is also faster in rendering.

Descendant selectors

Descendent selectors (using more than one element in a CSS rule) are inefficient in rendering, but I won’t give that up. I like to be specific about what element I want to select in CSS. I rather write div.column1 div.article span.date than span.date. The latter is more efficient, but that only works with very small websites because only then you’d still have an overview of the all classes that are in the HTML code.

When I write JavaScript code I try not to ‘pollute’ the global namespace. I try to do the same with CSS by using descendent selectors.

If you need faster rendering, you could alter descendant selectors by making one class that incorporates the whole path. So you’ll get span.column1_article_date instead of div.column1 div.article span.date. Although it would render faster, it also has some drawbacks. Renaming a class afterwards is tedious work, the class names can become very long and the classes can be used outside it’s intended containers, so a class called div.column1_article_date could be used anywhere in the DOM and not just inside div with the class column1.

ID’s and JavaScript

I do use ID’s by the way, Not in CSS though, but for JavaScript for these reasons:

  • Specific elements can be easily accessed in plain JavaScript with getElementById.
  • If an element has an ID, I can be pretty surre that there is a bit of JavaScript attached to it.
  • Using ID’s in your jQuery selectors makes the selectors less dependent on the current HTML structure. It’s easy to break existing jQuery selectors by removing a class in the DOM.
Bookmark and Share
11 Responses
Follow responses to this entry through this RSS.
  1. Matthew Fedak

    Interesting read, its really important I know on typical websites but making sure the css is as simple as possible, not too much duplication and then compresses (remove all comments, white-space) and enabling gZip compression at server level too can pay dividends on large css files. Also try to avoid having lots of css files and just have one as less requests is again faster. nice read though, you must have been pretty bored.

  2. Henrik Hofmeister

    Just a note on the last part:
    Using ID’s in your jQuery selectors makes the selectors less dependent on the current HTML structure. It’s easy to break existing jQuery selectors by removing a class in the DOM.

    You could also just prefix your javascript specific css classes (eg. “.js-mapcontainer”) – which will show you very clearly that an element should be attached to js (and an indication of what).. also it allows for attaching click and other event handlers to all elements within a container – for instance:
    someContainer.find(”a.js-view”).click(function() { /* handle event */ }) );
    or even
    someContainer.live(”a.js-view”).click(function() { /* handle event */ }) );
    I personally use several prefixes – depending on what kind of js im binding – and the source (std library or custom etc.)

  3. Wouter Bos

    Great comment! I couldn’t agree more. I too use a special prefix. I always do “tag_classname”. I wonder if there’s some (quasi-)official standard for that.

  4. Kevin

    How did you test the rendering time? Was it just visual, or were you able to get the actual rendering time via a utility?

    Also, I shy away from including the tag name in my class name. This creates an inflexibility when applying class names, since you can never switch out your tag names w/o the class name being out of sync. Probably a minor issue, but thought I’d mention it.

  5. Kevin

    I should have also mentioned that I agree with the overall sentiment of this article. I think CSS rendering time is probably the least of our worries as far as performance goes. And the changes we can make are so minor that only extremely bloated code will show a difference.

  6. Joacim Boive

    Very interesting read!

    But what about mobile browsers? I would guess it can be quite important.

    Maybe a followup is in order? And/Or if you could provide your test files that would be great!

    Thanks!

    /J

  7. Fabio Buda, Netdesign

    Your benchmark of CSS rendering time is a little confused…
    I think you should have done the test with the same very large HTML changing only the complexity of selectors deleting all * and putting real-life selectors.

    With your test (with very different pages) we have two different scenarios not fully comparable.

    But this is only my point of view :-) .

    Have a nice day of development,
    Fabio Buda,
    Web Developer/Designer @ netdesign

  8. Ben

    Any chance you could get the results but do it over a few hours in a loop or something?

    I.E. Will a page with inefficient selectors slow the browser down faster over time than a page with more efficient selectors?

  9. Wouter Bos

    I could, but I don’t know how realistic that situation would be. I already thought I took it to the extreme.

  10. Joey

    Hi, one detail bothers me – you say you found qualifying classes (.foo) with tags (a.foo) to be faster in rendering. That’s contradictory to what I read on Mozilla and eg http://www.vanseodesign.com/css/css-selector-performance/ – take a look. They both recommend using just .class. Or do I overlook sth?

  11. Wouter Bos

    Erm. No, Joey, You’re absolutely right. I changed my writing habits since this article. I only use classes in selectors whenever I can. Actually, I had forgotten about this article.
    But the main message still stands: don’t mind CSS selector performance, focus on maintainability.

Leave a response