Keep your CSS selectors short

One thing I believe, as a very, very general rule of thumb, is that as sites get bigger, selectors should get shorter.

By this I mean that if you want to create extensible and maintainable, flexible and predictable websites, you should really take care to make your CSS selectors as dev-friendly as possible; i.e. short.

Keeping CSS selectors short helps with a lot of things:

This is a very vague list, so I’m going to address each in order. You will find that there is a lot of crossover between each point (e.g. reducing location dependency inherently means your selectors are more portable) but I feel they are all points in their own right.

Increases selector efficiency

I have written before about CSS selector efficiency. I’m going to gloss over a lot of the intricacies in this post so for a full background understanding I recommend you read Writing efficient CSS selectors first.

If we ignore actual types of selector (*{} is typically the slowest, depending on how it’s being used, IDs are the fastest followed by classes, descendants are comparably quite slow followed by pseudo-selectors) then in general it is safe to say that shorter selectors are faster.

This stands to reason, if we compare these two selectors:

html body .header .nav{}
.nav{}

There we can see pretty clearly that in the first example, the browser has to look out for four things, the .nav class, then the .header class, then the body element and then, finally, the html element (browsers read selectors right-to-left).

With the second example the browser only needs to look for one thing; the .nav class. The browser has four times less work to do to match that selector. Every time you write a selector try and trim as much losable stuff from it as possible. Instead of ul.nav{} (two checks) write .nav{} (one check). Instead of .nav li a{} (three) write .nav a{} (two).

Now, CSS selector performance is—by-and-large—not something we really need to worry about any more, but that doesn’t mean we should be wasteful. I’m sure none of us would miss a lost £5 but that doesn’t mean we go slipping banknotes into paper shredders… Selector efficiency does exist and you might as well improve it where you very easily can.

Reduces location dependency

By keeping selectors short you are likely to be reducing the amount of descendant (e.g. .sidebar .promo{}) and child (e.g. .sidebar > .promo{}) selectors. By removing these descending types of selectors you are reducing the necessity for an element to live inside another one. Let’s reuse the .sidebar .promo{} example…

By having a selector like .sidebar .promo{} we are saying we want to target any promotional item that lives in an element with the class of .sidebar. This means that we are tied to always using that styling inside a certain element; we have a dependency on location.

By replacing .sidebar .promo{} with something like .secondary-promo{} we can now place the element in question anywhere we wish. In the sidebar—as before—but now also in the footer, or in the header, or after an article.

By reducing descendants we can really reduce dependency and make things a lot more portable…

Increases portability

So now that we’re not tied to locationally dependant selectors, we find that our components are a lot more portable. We can move things a lot more easily because our CSS doesn’t care where a thing lives, it just cares that it exists. Awesome!

Another way to increase portability is to not qualify selectors. A qualified selector is one like ul.nav{} or a.button{} or div.content{}.

Qualified selectors are bad because they reduce efficiency (more checks than we really need) but—more importantly—because they tie us to specific elements. We can’t now use that .button class on an <input> or a <button>, for example. We can’t apply .nav to an <ol> to make a breadcrumb.

Selectors should be element-agnostic. Your CSS shouldn’t care what element you’re wanting to apply styling to.

Another way to make selectors more portable is to drop elements altogether. Take this, for example:

/* Base widget styling */
.widget{}

/* Style up widget titles */
.widget > h2{}

Here we have a troublesome selector; what if that <h2> needs to become a <h3>? What if we need to add another, non-titling <h2> as a child of .widget? We’ve made ourselves a very rigid and unportable selector here. Instead we should have:

/* Base widget styling */
.widget{}

/* Style up widget titles */
.widget-title{}

Now we can apply .widget-title to any element—let’s say a <h4>—and can now also have any number of unclassed <h4>s in the widget without them adopting any title styling. Ossom!

Reduces chances of selector breakage

The longer a selector is, the more things the browser has to satisfy before it can match it. The more checks there are then—naturally—the more chance there is for something to go wrong.

A (very exaggerated) selector like body > div:nth-of-type(2) > article:first-child > p:first-child{}—borrowed from my talk Breaking Good Habits—has ten checks; ten things that must be satisfied in order for the browser to make that match.

All that needs to happen is the location of the div:nth-of-type(2) to change or the p:first-child to become a blockquote or the article:first-child to no longer be a child of the div:nth-of-type(2) or any manner of things before that selector will break. Simply replacing that with a class of .intro{} means that there is only one thing that could possibly break, and the chances of that happening are pretty much zero (you’d have to explicitly delete the class from your HTML to prevent a match).

Shorter selectors mean there is statistically less chance for things to go wrong.

Decreases specificity

This is the big one! This is where it really matters!

Longer selectors have a higher specificity. Specificity is a nightmare and you should keep specificity as low as possible all of the time. We already know that we do not use IDs in CSS but a chain of selectors are often just as bad (though not quite).

A selector like .widget > h2{} has a higher specificity (as well as the other problems we discussed) than a selector like .widget-title{}.

.nav li a{} has a higher specificity than .nav a (and is also less efficient). Reducing selector length reduces selector specificity and that is very important. High specificity leads to self-induced specificity battles that can only be won by making subsequent selectors more specific (or using !important, shame on you). This is a terrible thing. The easiest way to reduce specificity (after dropping IDs from your CSS completely) is to keep your selectors short.

Can make code more forgiving

This is a very specific but very decent example of how short selectors can make code more forgiving. However, I will warn you, you can argue two sides of what I’m about to tell you; you can argue that it makes your code a lot more flexible and can gracefully handle breakages or you could argue that it allows breakages in the first place by being too lenient. Anyway, here’s a true story…

In working on a pretty huge project at Sky I stuck to my own rules and coded a (vertical) nav bar CSS like so:

.nav{ /* Nav styles */ }

/* Note NO .nav li styles as this was a vertically stacking nav. */

.nav a{ display:block; /* More styles */ }

Now, there was a CMS error which went undetected where the markup getting spat out was:

<ul class=nav>
    <a href=#></a>
    <a href=#></a>
    <a href=#></a>
    <a href=#></a>
</ul>

Spot the problem? No <li>s! This is really not cool but, as I had used .nav a{} instead of .nav li a{} nothing broke. My code was a lot more forgiving than if I’d had that third check in there.

Now, this doesn’t make the markup right, and it does actually allow poorer markup than a more verbose selector, but you can see how the CSS was very forgiving of a markup error.

Now I said you could argue both sides here, a more verbose selector means that we’d have spotted the CMS error immediately as no styles would have hit the <a>s. But! In the same breath, our CSS was flexible enough to be okay with that. Make of it what you will, because I too am sat on the fence and a little disappointed that the error wasn’t spotted, but here is a very specific example of how shorter selectors can lead to more forgiving CSS.

Final word

I did mention that this is a rule I’ve applied to larger sites but, honestly, you should apply this everywhere. The things we’ve discussed tend to really come into their own (and their absence painfully aware) on larger builds, but they will definitely, definitely help you on builds of all sizes; small or large.

So, by using more classes and less descendants, keeping selectors short and portable, keeping selectors element-agnostic and generally considering maintenance and chance-of-change when writing our CSS, we can really easily improve the quality of our code infinitely. We can make things more efficient, more forgiving, more flexible and more reusable just by revisiting one of the most simple and fundamental aspects of CSS; our selectors.

By Harry Roberts on Tuesday, May 15th, 2012 in Web Development. Tags: , , , , | 25 Comments »

+

25 Responses to ‘Keep your CSS selectors short’


  1. Matt Lo said on 15 May, 2012 at 8:29 pm

    Hey Harry

    One thing I’d like to make a point is on the concept of deep level selector definitions in stylesheets. You made the example of using root level rule in replace of a specific four level deep selector. (`.nav{}` vs `html body .header .nav{}`)

    The concern here is you cannot be modular. Take the simple example of a header and footer navigation In my opinion the class label for /both/ the header and footer container should be `nav`. If you’re trying to reuse styles, wouldn’t it be more rules and an increased level of obscurity if selectors are all of a sudden agents of ID selectors?

    Another concern with your statement is code readability, I would argue specifying containers helps not only understand how the styles work, but how the application implements these styles. The lower the learning curve, the easier the handoff is (unless you’re a one man show)

    I understand your point about browser efficiency (which makes a great point on mobile devices) and it makes a lot of sense to be aware of your application’s footprint but that doesn’t warrant a code style change (not saying we have to anyways!). Having augmented namespaces, improved stylesheet readability, and lightweight rule reusability can be achieved without changing the style of coding.

    If your site is large enough where /this/ becomes an issue or if this is a large app on a mobile device, more likely a preprocessor that compresses and updates your styles and markup would be a very viable solution (look at Gmail as an example). `html body .header .nav{}` would become `.aA{}` and the output markup would changed. In addition to a build process for enterprise level applications, you can configure it to combine on all styles to `aA` without touching any of your code base.

    Performance can be improved without compromising conceptual coding guidelines and best practices. Especially in the CSS realm. All in all, I would say `html body .header .nav{}` is less obscured than `.nav{}`, which is the primary point.

    What are your thoughts?

    -Matt


  2. Harry Roberts said on 15 May, 2012 at 9:02 pm

    @Matt: I’m not sure I follow; I’m saying neep nesting is bad and should be avoided, a class like .nav is modular and can be extended (see http://prdesign-studio.co.uk/2011/09/the-nav-abstraction/ )

    “I would argue specifying containers helps not only understand how the styles work, but how the application implements these styles.”

    But they should work without those containers; needing the containers in your CSS is a bad thing and should be avoided.

    I am afraid I really don’t think I follow your points.

    Best, and apologies,
    H


  3. Brando said on 16 May, 2012 at 2:39 am

    Has anyone considered making CSS engines read left-to-right? I mean, surely they must have in the beginning. So, what are the technical reasons behind deciding to go right-to-left?

    It seems odd that it might be for efficiency when it’s the very thing that causes our CSS to render inefficiently as sites get complex and we potentially need added complexity. But then I know literally *zero* about the underlying technologies behind the rendering engines.

    The reason I bring this up is because I often find myself wanting to write selectors like this:

    .sidebar > *:first-child { margin-top: 0; }

    In a sidebar I want the first element — whichever type it happens to be — to give up its top margin so that it sits flush inside the sidebar’s element/border/background.

    But I can’t do that with a good conscience knowing that the universal selector is slow and that pseudo classes are too. Thus, I ended up with CSS like this:

    .sidebar h3, .sidebar p, .sidebar ul, .sidebar ol [...] { margin-top: 0; }

    It may be more efficient to render but it sucks to read and write.

    So, then I start wondering if I really need those elements to have top margins in the general sense. And that just strikes me as silly — all I want is for elements in this one spot not to have a top margin and now I’m considering removing top margins from them across the entire site!

    Surely there has to be a better way… Yes, I’m aware that CSS3 has or will have a selector that would help me here, but I’m more wondering why we have to put up with right-to-left selector matching when it might be nicer to use left-to-right.

    Any insights? Thanks!


  4. Larry Botha said on 16 May, 2012 at 8:06 am

    @Brando: Right to left is far more efficient as the number of iterations of a search for a matching element is greaty reduced.

    Imagine you have 1000 divs on a page, and only 1 of them has a child of .my-class. Using a selector such as

    div > .my-class { ...styles }

    with left-to-right reading would result in the parser first finding those 1000 divs, and then checking each and every one of those divs to see if they have an immediate child of .my-class.

    Right-to-left is far more efficient as the parser simply needs to find that 1 instance of .my-class, and then check whether its immediate parent is a div.

    What I’ve started doing for special case margin removal is creating reusable classes like so:

    .marginb-none { margin-bottom: 0;}

    If you need different values of margin (which hopefully you won’t), just append a different name:

    marginb-alpha { margin-bottom: 2em;}


  5. Christian Krammer said on 17 May, 2012 at 10:13 pm

    I really like, that these “concepts” (although they aren’t actually new) keep popping up everywhere now. SMACSS (http://smacss.com) pretty much goes the same way. However there is one thing I don’t like about adding additional classes to the HTML markup: CSS files get cached after you first load them, HTML files not. But it surely is a good thing to keep selectors short instead of limiting it to certain parent selectors.


  6. Chris Trude said on 21 May, 2012 at 5:11 pm

    While I agree we should be as efficient as we can be, I’m not sure efficiency in CSS code is really necessary at this day and age with speeds as they are. For me, I write as efficiently as possible, but the majority of the time, I am trumped by the need to have high specificity in my projects, mostly due to jQuery plugins being used by developers that have packaged css files that tend to overwrite my files that are less specific. Granted this isn’t an issue many people have, but I tend to come into projects to clean up the mess the developers have already made. Such is life. Nice article tho.


  7. Brian Hough said on 21 May, 2012 at 5:33 pm

    How do you feel about the use of preprocessors like LESS and SASS when it comes to this. I’ve noticed the length and specificity of selectors can get out of control with their nesting functionality. However, a lot of folks would argue that nesting is one of the nicest features of using them. Do you feel like there is a way to balance nesting, and keeping selectors shorter?


  8. J. reading said on 21 May, 2012 at 6:23 pm

    How is this:

    .hdr-nav {}

    …more dev friendly than this:

    header nav {}

    ?


  9. Leban Hyde said on 21 May, 2012 at 7:40 pm

    I have recently adopted the SMACSS approach (personal site excluded) and have to say that I love it. I have also researched OOCSS and BEM to give me a better perspective on the general approach. It took a bit for it to take hold, but it is worth the investment.

    There is something that just feels good about having smartly composed modular and portable CSS. You can reuse styles globally, keep the code base more manageable and the parsing efficient. If my base styles are solid, I can drop new elements into a page without them blowing up in my face due forgotten specificty.

    It does fly in the face of convention and, yes, there are moments that I feel that I am “dirtying” my markup with extraneous class names. If it feels like the classes are getting heavy in a specific instance, maybe that’s a sign that a new module/object needs to be broken out. At least, that’s my personal rule.

    I would encourage front-enders to at least try the approach on their own. You might be surprised ;-)


  10. Torben said on 22 May, 2012 at 8:19 am

    Interesting article. But i’m a little concerned, that the readability of the CSS code lacks if you try to use only one selector each…how do you keep your CSS code easily readable for everyone? Just with entering tabs? :)


  11. AucT said on 22 May, 2012 at 9:30 am

    imo better just write understandable code and then compress css by some of online css compresors.

    Also I want to say about first example
    html body .header .nav{}
    .nav{}
    i dont think everybody types html body .header .nav{}
    but we type .header .nav{} and .footer .nav{} or .sidebar .nav{}.
    I just want to say not in every cases u should decrease it to .nav

    However I think there is some true in ur post, but the profit isnt so big. I will try to less specify when it possible.

    P.s. huge thanks for ur horizontal navigation post


  12. Torben said on 22 May, 2012 at 10:56 am

    I have to recall my above comment a little bit, Harry. I read your other articles after this one and see how you make CSS-code readable for other developers.

    What i do is, that i often name the classes like the elements where i often use them. For example:

    I think this helps to keep CSS-code read friendly for everyone. What do you think?


  13. Andrew Mitton said on 22 May, 2012 at 8:00 pm

    Do preprocessors like SASS and LESS solve some of these problems?


  14. Harry Roberts said on 23 May, 2012 at 8:54 am

    Preprocessors would typically hinder here, rather than help. Their nesting features promote longer selectors.


  15. false said on 25 May, 2012 at 12:47 pm

    Can we apply all of this in JavaScript ?

    So in jQuery for example, $(’div#myClass’); is less efficient than $(’#myClass); ?


  16. Werner said on 27 May, 2012 at 3:33 pm

    What if you decide to change your entire site’s styles? Wouldn’t using classes everywhere hinder this? By using ID, element and class selectors, you abstract your CSS from your HTML allowing you to unplug one CSS file and plug-in another. Having classes everywhere will make it a hell of a job (and probably leave you with a lot of orphaned class attributes) if you make big changes to your site’s layout. Wasn’t the point of CSS to separate your styles from your HTML.


  17. tomandyourmom said on 28 May, 2012 at 4:05 pm

    @Werner – I agree wholeheartedly. I can’t say that I agree with anything I’ve seen on here. The idea of not using IDs for CSS is absolutely ridiculous, and shows a fundamental lack of understanding of the separation of concerns. If you’re using a list of classes to define the presentation of your elements, you’re doing it wrong.


  18. Aurélien said on 30 May, 2012 at 12:40 pm

    Great article.

    Got one question. In the paragraph ‘Reduces location dependency’ you wrote :

    “By replacing .sidebar .promo{} with something like .secondary-promo{} we can now place the element in question anywhere”.

    Wouldn’t it be simpler by replacing .sidebar .promo{} with .promo{} ?
    I mean what’s the point to give a new name to that class ?

    Thanks,
    Aurélien


  19. Harry Roberts said on 30 May, 2012 at 12:58 pm

    @Aurélien: Sorry, that’s lack of clarity on my part. By having .sidebar .promo I am assuming that a .promo already exists somewhere and in this case we are creating a new type of promo for the sidebar (i.e. a secondary type).


  20. Aurélien said on 30 May, 2012 at 2:27 pm

    Oh I see now ! That’s the point I was missing.

    Thanks a lot ;)


  21. Werner said on 6 June, 2012 at 8:35 pm

    I would much rather recommend this article, Decoupling HTML From CSS by Jonathan Snook on http://goo.gl/SudOo


  22. Adrian Westlake said on 7 June, 2012 at 2:45 pm

    I have started this approach in my latest work and it is much much nicer knowing that you can take a chunk of code and put it somewhere completely different without breaking anything. Strongly recommend this approach to anyone.


  23. Dathan Nicholson said on 15 June, 2012 at 8:33 pm

    I’m going to disagree for two reasons: 1, I hate cluttering the HTML with unnecessary arrtibutes, I keep the code as minimalisic as possible. 2, I use sass and nesting the selectors in a tree-like structure keeps things neat and organized and easy to trace. An unfortunate side-effect of SASS is the long selectors, however, I don’t care if the output is a minimized, obfuscated, garbled mess, on the maintainence side, SASS and minimal HTML is best.


  24. AntoxaGray said on 3 August, 2012 at 12:30 pm

    People writing «ul li ul li» instead of «ul li li» or even «li.lv-2» are stunning me.


Leave a Reply

Respond to Keep your CSS selectors short

Hi there, I am Harry Roberts. I am a 21 year old web developer from the UK. I Tweet and write about web standards, typography, best practices and everything in between. You should browse and search my archives and follow me on Twitter, 7,791 people do.

via Ad Packs