webdevjeff.us

Web Developer Jeff George

Blog

Relax! Don't do it!

Never us IDs as selectors in CSS. Ever. Really.

Sept. 29, 2015

When we're first learning CSS, we're taught three basic selectors to use to name our styling rules: elements, classes, and IDs. We're told that using elements as selectors (like <p> or <h1>) will apply a style rule to every instance of that element in our document, which has some utility. We're told that we can create classes as selectors that will apply a style rule only to the elements we choose, which is even more useful. And we're told that we can create IDs to style an element that occurs only once on the page, which sounds handy.

What we're not told is that just because we can create and use IDs for CSS styling, doesn't mean that we should do it. In fact, we should not do it. Ever. And here's why…

Bad reasons to use IDs as selectors

A handful of rationales have been offered for why it's OK to attach styling rules to IDs. Some assume that since Codecademy (and every other CSS intro on the web) shows you how to do it, it must be alright. Some do it because they've done it for years, and it has (almost) never caused a problem. Some say that since the IDs are already there (as link anchors or JavaScript selectors), it's just DRY ("Don't Repeat Yourself") coding practice to use them.

But these are all rationales, not reasons. The pattern of teaching new developers to use IDs as selectors goes more than a decade, when CSS was a primitive, optional enhancement to HTML, and not the equal partner it is today. Early versions of CSS tightly limited the number of classes you could create, and most basic sites were created using HTML alone, without CSS or Javascript. Back then, IDs were used mainly as mid-page targets for links, so there wasn't a lot less to mess up by having them serve double-duty as selectors. That's not true for today's much larger websites and more complex technologies. And as for DRY coding practices, IDs have more critical uses that don't even touch CSS; applying an ID to an element for your JavaScript and a separate CSS class to set it's appearance is not repeating yourself.

Some have argued that using IDs in place of classes improves browser performance, which is technically true but trivial to the point of irrelevance. Web dev blogger Oli Studholme ran empirical tests comparing browser performance using IDs and classes, and found that in a test accessing 1,000 elements in an HTML document, Chrome processed the 1,000 ID requests a grand total of 1.2 milliseconds faster than the 1,000 class requests. That means that using an ID as a selector instead of a class cuts your load time by 1.2 nanoseconds, or 0.0000012 seconds! You'll save your users more time by optimizing a single JPG image than you could in a lifetime of using IDs in place of classes.

Good reasons not to use IDs as selectors

There are several excellent reasons not to use IDs as CSS selectors. The most basic is that they already have two other important and closely-related functions: as unique identifiers for JavaScript, and as targets (anchors) for links to any destination other than the very top of the web page. Adding a third, very different function on top of that makes your code much more fragile and less maintainable. Imagine that you have used the same ID as an element handle used in a JavaScript method that allows your user to interact with the page, and as a selector to style that element. Then suppose fixing a bug in your JavaScript caused you to change the name of that ID. You've just broken your CSS, and your site isn't displaying properly anymore. If you'd used a separate class for the styling, you could change the ID to suit your JavaScript needs without fear of breaking anything.

Another compelling reason is that good CSS is re-usable CSS. You want your selectors and rules to be useful and applicable on a wide variety of elements, across many pages. Doing so (generally) makes your CSS file smaller, and your site more maintainable. IDs are just the opposite: each ID applies to only one element, and each element can have only one ID. For example, if you declare a class that turns text blue, .blue-text { color: blue; }, you can apply that class to any headline, paragraph, span, list item, sidebar, glyphicon, whatever. And if you do a special version of the site for Halloween, and want to turn the blue text orange just for the day, you just make one change: .blue-text { color: orange; }, which will instantly affect every instance of blue text on any page of the site. (And you can change it back just as easily on November 1). If you'd used IDs to style the color of your text, you'd have to go through every page of the site to make this change, looking for IDs with the declaration color: blue; buried among their rules.

But the most important and least understood reason not to use IDs as selectors is that IDs stomp all over other selectors. Because CSS's rules for the specifity of selectors prioritize IDs over classes, and classes over elements, any rules using an ID as their selector will take precedence over conflicting rules based on element or class selectors, regardless of their order in the CSS file. For example, imagine you apply these rules to same div element:

  • #my-id { background-color: red; }
  • .my-class { background-color: green; }

You might expect the background of that div to be green, because that rule comes after the one that turns the background red. But what actually happens is that the specificity of the ID overpowers that of the class, so the rule based on the ID selector gets displayed on your page. You wanted a green background, but you got a red one, because you styled an ID. Whoops!

Anything ID can do, class can do better

There's literally nothing good that CSS can do with an ID that it can't do better with a class. If you use only classes as your selectors, and never use IDs, you'll keep your CSS "flat," meaning that your rules will have more uniform specifity, and you'll be able to expect the later rules in your style cascade to overwrite earlier ones. You don't "save" anything by multi-purposing an ID as a CSS selector; modern CSS can handle a virtually unlimited classes on every page. But ID selectors do make your site more prone to bugs and errors, and more difficult to maintain. Because you can apply classes to more than one element, and more than one class to any single element, classes are infinitely re-usable and combinable, making your code more flexible, extensible, and compact.

If you really need a unique selector, you can just create a single-use class. You can even give it the exact string for both its ID and class names! That is, you can have an element like:

  • <button id="submit-btn" class="submit-btn">

When you see "#submit-btn" in your JavaScript and ".submit-btn" in your CSS, you won't have any trouble remembering that you're talking about the same button. But if you are careful to attach your styling to the class (.submit-btn), you won't break your page if you later need to change the ID of that button. Perhaps you'll later add a second submit button to a form on another part of the page. For clarity, you might change the ID of the original button to #submit-btn-1, and ID the second one #submit-btn-2. You could then style both buttons by applying the single class .submit-btn to each of them, instead of having to add a separate set of identical style rules for #submit-btn-2 (which is the exact opposite of DRY coding, btw!).

The bottom line is this: Save IDs for your JavaScript and link targets. Use classes to style your page. You'll get more sleep that way.