Using IDs in CSS
The conversation so far
On one side we have a group of experienced CSS developers who say that it is advisable to use ID selectors as little as possible.
The reasons are generally simple:
- The ID selector’s high specificity will bite you down the line as you update a property elsewhere and wonder why it isn’t appearing.
- It increases the chance of something going wrong when you are working with collaborators as ID’s high specificity smashes other people’s CSS.
- Styles attached to IDs aren’t reusable on other elements (you can only have one of each ID per page).
- The performance benefits are negligible and don’t outweigh the problems.
The counter-argument, most eloquently outlined by the eminent Zeldman (don’t forget to read the comments as well), are equally simple. They roughly go as follows:
- IDs have meaning. Tying styles to the semantics of the document is generally more desirable than tying them to the more generic structure of the document.
- When a single element has a unique style, the only sensible way of applying those styles is with an ID. If you have only one of that element, giving it only a class undervalues it.
- People who avoid IDs do so because they don’t understand selector specificity and the cascade.
- Markup should be structured for humans and IDs have an important role in conveying the meaning of the markup, so it should not be avoided.
- Problems arise because the coder is inept, not because the thing itself is problematic.
- Most sites are maintained by just one web developer. Teams are an edge case.
- If you use IDs sparingly, semantically, and structurally in the correct way, you won’t have problems. The corollary being that if you do run into problems you must have been doing something wrong and that it’s your own damn fault.
Both sides are actually correct, depending on the circumstance. However, in my own practice, I’ve landed firmly on the ‘no IDs in CSS’ side for reasons that go beyond those outlined by others.
So, these are my reasons. Feel free to ignore.
Collaboration
First of all, every complex project is a collaboration, even if you are working on it alone. The collaborator? Your future self.
Unless you have perfect memory there is no way you can pick up a stylesheet a year later and still retain a perfect mental model of the specificities of its selectors. If you were using IDs in the original, you are going to run into problems when you revisit the stylesheet a year later. I’ve run into this several times in my career.
IDs add complexity that make collaboration more problematic, even in teams of one.
Styles don’t need that much specificity
I agree with Zeldman that if you have an unique element, using an ID selector to apply its unique styles is not only preferable, it is the right way to do it.
The problem is that in most designs, unique – single element – styles are actually quite rare, generally only limited to positioning and modifying existing design elements. Most headers are composed of design features that are shared across many elements. The combination may be unique and the positioning of the header is unique, but that doesn’t leave much for the ID selector to do.
Also, using the ID selector in this context risks making it difficult for you to reuse those elements if it turns out they weren’t that unique. This happens all the time as you code up a website’s design.
So, even if you agree with Zeldman, that still means that you aren’t going to be using ID selectors much at all, mostly as singleton objects with a few, highly specific, properties.
IDs are over-loaded
Another thing many people misunderstand is that the idea is to avoid ID selectors, not to avoid IDs.
IDs used to only really be used by CSS and by anchors for links. Today, IDs play a central role in technologies as diverse as ARIA, scripting, links, and microdata. Everything is hooked into IDs.
Developing websites isn’t a waterfall-type process, where you first structure the markup, then the styles, before moving onto the scripting and accessibility. Making websites is an iterative process and when everything is too tightly coupled to IDs (or too tightly coupled, period), it’s very easy to break something in one area when you are working in another. Changing an ID when you’re working on the CSS can break the javascript and ARIA integration. You might notice the javascript breaking, but a lot of teams won’t notice their accessibility features breaking because they test them rarely.
Even if we don’t use ID selectors in our stylesheets our markup will still be littered with IDs because they are used by so many different layers of the web stack. CSS is the layer that is the most easily decoupled from IDs.
(RDFa Lite is unique among recent web technologies in how it approaches ID-like behaviour. It very sensibly proposes an analogous attribute called resource, enabling RDFa Lite markup to be integrated with a page’s markup without being tightly coupled and without inviting the fragility that comes with tight coupling.)
Loose versus tight coupling
One of the thing computing gurus such as Alan Kay have been harping on about since the late seventies is loose coupling. Systems that are built out of tightly coupled objects are more fragile and less dynamic than systems built out of loosely coupled elements. (Which is why ‘message-passing’ is one of the most important part of Alan Kay’s initial vision of object-oriented computing.)
IDs are already tightly coupled to so many of the web’s building blocks:
- Links. Can’t do anchored links without them.
- ARIA. Many of ARIA’s essential capabilities require either being tied to IDs or to specific markup structure.
- Scripting. You can do scripting without using IDs in any way, especially now that selector queries are so widely supported, but while the performance advantage to ID use in CSS is negligible, in javascript the difference can be substantial for some apps.
The only one technology that can, with great ease, be used with only loose coupling to the same, hard-coded, elements as all of the other layers are using, is CSS. By breaking down your styles into class-based building blocks and avoiding over-using both ID and element selectors your stylesheet can be more more flexible to use and more resistant to breaking as other people work on the site’s scripts and behaviour.
(Incidentally, I recommend Jonathan Snook’s Scalable and Modular Architecture for CSS for more information on this approach to CSS.)
There is freedom and flexibility in delegating ID use exclusively to links and behaviour.
Tightly coupled CSS makes everybody’s work more difficult. Loose coupling makes it easier.
The advice
This isn’t to say that ID selectors must be avoided by everybody everywhere. The above are my concerns for my projects and they may or may not be shared by others.
Overall, my advice can be broken down as follows:
- If you are alone or in a small team working on a content website or ebook, ID selectors can be a powerful tool if used sparingly. Religiously avoiding them is silly in this context. Just bear in mind that an ID selector implies that the attached visual styles are unique to that IDed context and will never be used anywhere else.
- If you are working on an ecommerce site, ID selectors are generally more trouble than they are worth. Most ecommerce sites aren’t actually composed of a single system but usually loosely integrated CMSes, shopping carts, payment systems, support systems, with maybe even a separate blog thrown into the mix. And they are usually supposed to share a design across these systems. Each system is often maintained by its own service provider. ID selectors and the integration they imply quickly become a hassle.
- If you are a part of a team working on a web app, for the love of $deity don’t use ID selectors. Writing a best-of-breed application in javascript is hard enough. Give javascript the sole responsibility of using and managing IDs and of attaching ARIA properties. It’ll cause fewer problems in the long run.
As a general rule of thumb: if the only thing likely to refer to IDs is your CSS, go ahead and use ID selectors. If more than just CSS or links refer to the IDs, try to use ID selectors as little as possible. If you are working in a team, try to avoid them.