Hacker News new | comments | show | ask | jobs | submit login
Writing efficient CSS selectors (csswizardry.com)
88 points by webista on Feb 28, 2013 | hide | past | web | favorite | 40 comments



Note that this article is from 2011.

Trying his tests on firefox 20 beta, shows no difference between id and class selectors (the article says there was minimal difference in ff6), also no difference between between the type and "heavily overqualified descendant" selectors (article reports a large difference) and the latter pair are approximately twice faster than the former (the article seems to report they were up to 40 times slower).

So beware that browser technology has progressed since the time of this writing. Of course once again you should be checking the behavior of your site with the browsers your users are actually using.

[Edit: originally confused the two pairs of tests in my browser tabs, the slow tests in ff6 are actually the faster tests in ff20]


Yep, I should probably add something to the article about this; browsers now are so fast that tests show little to no difference :)


Browser makers have also done a fair bit of work to speed up the selectors - I'll see if I can find the article


The only reason id selectors would be faster (that I can think of) is that ids are supposed to be unique, so the matching can stop after finding the first element with an id. However, none of the browsers I tested this in actually did so. Here's an example:

http://jsfiddle.net/zsjrN/

Only the first paragraph should be red.


The only time I've known that the uniqueness of ids to be in play is either as a target of an anchor or to be used in Javascript. As far as I know, in those cases only the first element with that id will be involved.

Removing the CSS from your example, and then using Javascript to change the color you see that only the first one is altered.

http://jsfiddle.net/KQkJE/1/

So, in terms of CSS, it doesn't really matter. Well, I don't know about performance issues with it though. But for Javascript it matters a great deal. As for HTML, it only really matters in that it's supposed to be unique for anchor targets, which would be one reason it doesn't validate.

Browsers give a great deal of leeway when it comes to HTML and CSS, because so many people and editors do not follow the spec. Of course, you could argue that no one follows the spec because the browsers don't really enforce it. I've been constantly amazed over the years seeing various examples of HTML soup that should not render in any recognizable form that somehow renders in the browser.


There are a lot of "supposed to" rules in HTML and CSS that many people violate in practice, and browsers for the most part try to accomodate that if they can. Not surprised to hear that non-unique ids are permitted.


Ids are supposed to be unique but I don't think that browsers are supposed to assume that they are.


In practice, since so many web developers violate the rule about ids being unique, I think browser devs are forced to make the ID map into a multi-map, which makes it exactly the same as the class map.


A lot of great information here. I always knew that overqualifying selectors was bad, but it was always from a "clean code" point of view and not so much from a performance standpoint. Even more reason to avoid them now.

Although this is very interesting information, anyone reading this article should pay careful attention to the ending headline, "Is all this really necessary?" Odds are, unless you've produced some kind of CSS monstrosity, your CSS isn't the bottleneck in your website performance. Min and concat your Javascript, use appcache, local storage, etc. before prioritizing CSS performance.


Hey, article author here :)

> A lot of great information here.

Thanks!

> …unless you've produced some kind of CSS monstrosity, your CSS isn't the bottleneck in your website performance.

You’re definitely right insofar as selector efficiency should be last on your list of things-to-make-my-site-faster. CSS as a whole, however, is a pretty significant performance concern; I wrote a little more about that here: http://csswizardry.com/2013/01/front-end-performance-for-web... </plug>

Cheers! H


Maybe a dumb question, but if you are making one of these larger sites, and you add classes to everything because there are "100s of <a> tags" ... does all the added bytes to the HTML matter less than the time it takes to parse CSS? or does it not make any difference, I guess we're talking about milliseconds here? Would some people choose to push it onto the client and reduce their bandwidth?


Is there a performance difference between using "div#container" and "#container"? When reading the css, I find it easier to be reminded that the element with the id container is a div element, but I guess its an additional check for the browser right?


Qualifying selectors like that is always a bad idea because:

1) What if you ever need to use the selector on a different element? 2) A performance hit (though so slight it might as well not matter) 3) Increased specificity

I have written a lot about CSS selectors:

http://csswizardry.com/2012/05/keep-your-css-selectors-short... http://csswizardry.com/2012/07/quasi-qualified-css-selectors... http://csswizardry.com/2012/07/shoot-to-kill-css-selector-in...

H


Thanks for the reply and the links, I will check them out. :)


Please read this, CSS Selector Performance has changed! (For the better)

http://calendar.perfplanet.com/2011/css-selector-performance...


The most important piece of this is somewhat between the lines here though I think he kind of comes out and says it at some points (I'd recommend you check out his SpeakerDeck presentation[1] which mentions this too).

CSS efficiency is a balancing act between best practices, speed, and maintainability. CSS rendering is really cheap compared to JavaScript or most other things, HTML excluded. So yeah, be aware of efficiency but don't let it come at the expense of maintainability. If you add a "non-semantic" class here or there so another developer can immediately understand what you're doing it's not going to be the end of the world and in fact is probably the right thing to do, efficiency be damned.

What I always try to do is identify patterns and use IDs and classes accordingly. So, for example, I've got an app that displays success and error messages based on input. I originally (and stupidly) gave each one its own class (i.e. '.user-signup-error' or '.save-file-error'). That wasn't going to scale. So I went back in and gave each type of design element it's own generic class. So now there are things like ".notification-box" and ".error-msg". All elements of that type will be notification-box'es and be given a default style then I'll have another class added to the same element indicating the type of message. IDs are real useful for giving JS something to hook onto but otherwise HTML5 has allowed us to now get rid of a lot of those #nav, #header, #sidebar IDs and instead just use the appropriate element name (nav, header, aside, footer, etc.) which is pretty cool.

All in all though, this is something to be aware of but not to worry too much about. Being too strict about efficiency can be just as bad as being overly inefficient.

[1]https://speakerdeck.com/csswizardry/breaking-good-habits-1


These are always interesting articles, but rarely of practical value. Performance is only one concern of a website project. I've found that a greater risk by far is predictable modularization, a topic with much less "engineering" attention. Any decent-sized project is going to have to decompose their presentation declarations info manageable artifacts, which has the unwanted side-effect of spreading out existing selectors across multiple files. Add to this a tight project timeframe, several engineers that treat CSS as a second-rate language (as almost all that I've encountered do, worsening the more senior they are), and CSS' lack of selector-spacing (in the namespace sense), and you have a recipe for thermonuclear battles over selector specificity.

Selector and naming conventions can basically eliminate this problem. Module root elements have a class name that starts with a letter; module nested elements have a class name that starts with a dash. These are combined with the child selector to constrain their applicability.

What was once super-ambiguous, e.g.

  body { color: black; }
  .menu .item { color: orange; }
  .menu .item .menu { color: black; }
  .menu .item .menu .item { color: orange; }
  /* and on */
is now very precise:

  body { color: black; }
  .menu > .-item { color: orange; }
Is it the most efficiently interpreted ruleset? No, and I don't care. It's the most efficiently manageable ruleset. (Web Components will probably obviate this.)


I think it's also good practice to check if you can reduce your DOM.

  <ul id="social">
    <li><a href="#" class="social-link twitter">Twitter</a></li>
    <li><a href="#" class="social-link facebook">Facebook</a></li>
    <li><a href="#" class="social-link dribble">Dribbble</a></li>
    <li><a href="#" class="social-link gplus">Google+</a></li>
  </ul>
could be written as:

  <a href="#" class="social-link twitter">Twitter</a>
  <a href="#" class="social-link facebook">Facebook</a>
  <a href="#" class="social-link dribble">Dribbble</a>
  <a href="#" class="social-link gplus">Google+</a>
since you already have the social-link classes attached to it.

Another example. This:

  <div id="header"><h1>header</h1></div>
could be written as:

  <h1>header</h1>
since you should have only one H1 on your page.


For your first example, I would argue the following is better. You reduce repetition of the class name and keep the semantic value of having a list

    <ul class="social-links">
        <li><a href="#" class="twitter">Twitter</a></li>
        <li><a href="#" class="facebook">Facebook</a></li>
        <li><a href="#" class="dribble">Dribbble</a></li>
        <li><a href="#" class="gplus">Google+</a></li>
    </ul>
You would need to have a scary size document to reap the benefit of reducing your element nesting level by that little.

Also if you don't want to commit to having a h1 as always being the header, using a class for the styling would be beneficial.

    <h1 class="header">header</h1>
Or depending on your situation you might want to use a header tag.


I think OOCSS has a strong influence on this use of multiple classes instead of your example of nesting classes (which i would have done, too).

I'm not saying I totally agree, but OOCSS promotes the idea that your styles should be decoupled from your HTML structure. This makes CSS easier to maintain.


Or maybe better, a fictitious attribute...

<a action="share">Share this article.</a>

Or better still, just have that as an option in the browser. Tada - 100% minimisation!


He was using the example from the article - did you read it?


For your first example it depends on various factors. Sometimes having the links inside a list is more efficient in terms of styling versus having a series of repeating anchors. Then again, in most cases you can just as easily wrap the anchors in a div with similar outcomes.

About this:

  <div id="header"><h1>header</h1></div>
There are reasons to do this. If all your doing is simply wrapping a block element with a block element then that's likely not a good idea. You are right in that if any styling done to the div can be done to the h1 then you might as well skip using the div in the first place.

One reason to do that is for a header with a defined size that has a background image for display and the h1 is text inside that header that can be placed via positioning. Although more than likely the h1 is not a good choice for that role.


In HTML5, it's fine to have multiple `h1` tags on the page, though you can only have 1 in each `section`.


It's worth mentioning that in HTML 5.1 they are now recommending that you use headings with an appropriate rank. Not that it's wrong to have multiple H1 tags, just not recommended anymore.

Exact wording: Sections may contain headings of any rank, but authors are strongly encouraged to use headings of the appropriate rank for the section's nesting level.

http://www.w3.org/html/wg/drafts/html/master/sections.html#h...


Hmmm, interesting. So that's going in the other direction to the HTML5 spec, in which you considered a header in relation to the section it's contained in, without worrying about the section's relation to the whole document. It was the browser's job to do the latter.

I will keep an eye on this. Thanks for the pointer.


In case you're interested, this is the bug report that resulted in the change: https://www.w3.org/Bugs/Public/show_bug.cgi?id=19741

The final editor's response explains the reasoning: "Change removed advice recommending use of h1 elements as the utline algorithm has virtually no implementations and as a result use of h1 elements flattens document outlines for users who actually consume the heading semantics. While use of elements of the appropriate rank for the section's nesting level is backwards compatible"


Thanks for that. I had assumed the header structures was one of the more stable parts of the spec!


I know it's fine, but I think you shouldn't because of SEO.

But to keep this on topic: my point is: a lot of time you can reduce your DOM.


Even then, it's fine as long as you're structuring your page sensibly. For example, on a blog index where each blog post is in a section, it's fine for each blog title to be a h1.

Matt Cutts talking about this: http://www.youtube.com/watch?feature=player_embedded&v=G...!


As I understand it, the whole "SEO mandates one h1 per site" is outdated. Search engines (read, Google) now follow HTML5 specs and, if you are doing your semantic tagging right, multiple h1 aren't a concern anymore.


It's worth noting that this is from 2011. Here's some more discussion on the topic:

https://developers.google.com/speed/docs/best-practices/rend... https://developer.mozilla.org/en-US/docs/CSS/Writing_Efficie...


Do really selectors work that way?

I always though that if I had:

#social a

The browser first get the social, then the "a" tag and analyze and store it in some DOM tree style information.


I thought the same. If this is true (it finds <a> elements then looks for the id), I've been writing a lot of poor-performing selectors.

Edit: I found that it does work this way, and the reason is because browsers process content and apply CSS top to bottom as it renders, they do not first load all the content and then apply CSS rules.

From http://snook.ca/archives/html_and_css/css-parent-selectors

If you have a rule like body div#content p { color: #003366; } then for every element—as it gets rendered to the page—it'll first ask if it's a paragraph element. If it is, it'll work its way up the DOM and ask if it's a div with an ID of content. If it finds what it's looking for, it'll continue its way up the DOM until it reaches the body.


Yes, selectors really match from right to left

Boris Zbarsky gives a good explanation of why here: http://stackoverflow.com/questions/5797014/why-do-browsers-m...


That bit certainly surprised me. It seems like a simple optimization to scan a selector for the most efficient parts and use that as your starting point (with ids being a no-brainer).

Obviously given the selector "div #foo a {}" (obviously a dumb selector, but...) it would be smarter to look for #foo and verify it was inside a div than get every div and search for a #foo. And by extension "div .foo a {}" (assuming .foo really is way more efficient than div, which again I find hard to believe given there's native support for getElementsByTagType).

It seems to me that the effectiveness of using classes probably stems from browsers optimizing against use cases like "OMG folks are using Dijit and hanging twelve classes off every div". There's no reason I can see why class selectors ought to be especially efficient, especially if -- say -- your markup has lots of classes and relatively few attributes (and isn't that more common these days?).

We should also probably differentiate between CSS selectors as affects page rendering and CSS selectors as affects grabbing a bag of nodes using jQuery $() or document.querySelectorAll().



I find it interesting that instead of using tags to target a list-item, it suggests putting a class on every li in the HTML. Seems rather bloating to the HMTL if you have a number of long lists.

Is using descendant selectors in that case bad enough to offset all those class attributes? I think I'd rather put a class on the ul or ol so that I can target the parents if needed and then can still easily target the li children.


I've created dozens of sites and never really noticed any CSS performance issues.

I have got orders of magnitude faster sites by combining CSS or js files, gzipping content, adding cache control headers, serving via a cdn and not serving code that's not used.

I've also really benefitted from using logical markup and CSS selectors, not those designed for "efficiency" of the computer rendering them.


If you are done with the obvious optimizations, at some point you spend half a day to gain 50 ms on the backend. And that's a good day. If you are able to achieve 25 ms on the frontend in half an hour, it's worth considering. E.g. Font Awesome [1] is very popular, but the selector performance is horrible.

[1] http://fortawesome.github.com/Font-Awesome/




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: