In defense of the humble id attribute

Recently on my post about quoting HTML5 attributes, Paul Irish commented in passing

IDs are totally out of fashion now due to their high specificity so who cares

This idea has been floating around for a while.

Dave Gregory wrote Don’t use ID selectors in CSS almost exactly 3 years ago, observing the following.

  • The element is not re-usable on that page.
  • This is the beginning of a downward sprial into specificity.
  • Usually, IDs refer to something very specific, and abstracting would be tough.
  • Any performance gains picked up by using id, is negated by adding any other selector to the left fo that id.

The cat really got set among the pigeons when CSS Lint, a tool to help developers spot errors and adhere to good practice included a warning when your CSS uses id selectors.

One of CSS’s benefits is the ability to reuse style rules in multiple places. When you start out with an ID selector, you’re automatically limiting that style to a single element

Now, I’m far from the first person to have concerns with this recommendation. Matt Wilcox provided a detailed critique of a number of different practices he had concerns with.

In short: don’t blindly follow the crap these tools tell you. Chances are very high you’ll do yourself more harm than good, ending up with harder to maintain, bloated code, with nary a change in how fast your site feels.

The criticisms of the use of id are almost invariably about its shortcomings when used in CSS. But id is for more than just providing styling hooks.

I’ve got this crazy idea about developing for the web. These days it’s referred to as “content out”. The idea is that the content of the page drives the design. By marking up the page content as meaningfully as we can, we surface that content, and the associated functionality of the page. Then how we present this content is driven by the content.

In the semantically impoverished markup language that HTML has always been, ids allow us to say something about the content of a page. We can use it to uniquely identify an element on a page. The masthead. The site level navigation, the main content (yes I know about the proposed main element in HTML). Some things are unique within a page. At times it makes sense to identify these.

ids are for more than simply denoting unique elements within a page. As fragment identifiers, they allow us to link directly to part of a page (both within our own site, or to other sites entirely). They atomize web content, breaking down the monolithic page level structure of the web to arbitrarily small fragments.

They’re also obviously used with input (and related form) elements, to associate labels with these elements, and submit for content.

And of course, we can use the id to access elements in the DOM via JavaScript, either old school style using document.getElementsById, or new school style document.querySelectorAll('#idname').

So, the suggestion that we don’t use id attributes in any circumstance is contentious at best, I’d argue overly limiting, and in some cases impossible to follow.

Now, if we actually have id attributes on elements, why not use them with CSS selectors? The critique of using them with CSS is motivated by two primary concerns.

  • They’re overly specific.
  • They limit the reuse of CSS within a page.

Let’s look at each of these concerns in detail.

id selectors are overly specific

The id selector in CSS is very powerful. A single id alone will trump any real world combination of other selectors. So, the only way to over-ride style assigned using an id selector is to use more id selectors. In my own work over many years, I can’t actually recall this being an issue, but my work is typically done in very small teams that can work collaboratively, or alone. Where multiple developers work independently on a site I can see this as being more of an issue.

However, rather than the blanket rule applying to all situations, it should be applied in context. Where the over-specificity of ids may have an impact, such as where multiple independent teams work on CSS that might impact on a page, this rule may well make sense. In many other situations it strikes me as overly pedantic and restricting. If we can’t use id selectors, then anywhere we have an element with an id, we’ll also need a class attribute. Which in essence is adding class purely for stylistic purposes, contradicting the very well established practice of separating our semantics from our presentation.

But, if you’re really concerned about using an id selector due to its specificity, there’s the attribute selector. Attribute selectors allow us to select elements based on the presence, and value, of any attribute on an element. Since ids are attributes, attribute selectors apply equally to them as they do to class, href, alt or any other attribute. But, whereas id selectors have a very high specificity, attribute selectors all have the same specificity as the class selector.

For example, #main {} has a specificity of 100, while, *[id="main"] has a specificity of 10.

So, we can use the id attribute to select elements to style, but now the style assigned to an element via their id won’t trump that applied via class.

ids restrict reuse of style within a page

What about the second concern, that because ids are unique to a page, then if we create style for a particular element, we can’t reuse this style on the page. To me this is rather putting the cart ahead of the horse. My argument would be: if we have unique elements on a page, and if our appearance of these elements is a function of the unique element that they are, why not use their id? If a page has a unique header (as opposed to the sections of the page which may have their own header elements), and, as is likely, the h1 element of the page header appears differently from all the other h1 elements on the page (we’re using the HTML5 outlining approach, of course!), why wouldn’t we use the specific semantic aspects of the element to assign its style? If an element also plays a particular role, or belongs to a particular class of elements, then style that is a function of these aspects of the element should of course be assigned based on these characteristics (selectors of the form .classname, or [role=]).

Yes, styling via id restricts the reuse of style. At times that’s exactly what we want!

The politics of CSS

Recently, I had the privilege to hear Angus Croll present, The Politics of JavaScript. Luckily, you can see it too, as we’ve put the video of the presentation online. In it, Angus brings a critical eye to a number of “best practices” that he feels have over time been adopted unthinkingly. I have a lot of sympathy for this position (though Nicholas Zakas (co-developer it so happens of CSS Lint) presents a countervailing point that is also well worth the time reading).

Ultimately, Angus’s point is we should understand the rules, practices and guidelines, and adopt these, or not, with an understanding of the benefits they bring, and the costs that come with them.

I guess this post is really trying to bring some of that spirit to a particular guideline I’ve never been comfortable with, one which at least shouldn’t be adopted unthinkingly.

Perhaps my suggestion to Nicholas, and Nicole Sullivan, the original developers of CSS Lint would be to, where flagging the use of id selectors, suggest the alternative of using the attribute selector? To me it goes a long way to addressing the concern of the specificity of id selectors limiting their usefulness, while allowing for the ongoing use, and usefulness of a markup practice that’s been around, and widely used, for many a long year.

People mentioned in this post

Technologies mentioned in this post

17 responses to “In defense of the humble id attribute”:

  1. Great article and I have always agreed with this mentality. Avoidance of CSS IDs is just silly in many situations, causing problems where none exist.

    I noticed a minor typo referencing the “old school” document.getElementsById which should be document.getElementById

  2. Interesting alternative. I’m wondering about the performance difference for an attrbute selector. We may have decided that in most cases CSS performance issues are negligible and rendered moot by dropping or better compressing a few images, but I doubt that was considered with a large stack of attribute selectors in mind.

    • By: Paul
    • July 11th, 2013

    I agree with you wholeheartedly. I use Id’s in my markup all the time for reasons you mentioned above. I however do not target Id’s in my css. I do always ask myself when writing css and markup:

    Is it semantic?
    Is it accessible?
    How will it scale? (situational depending on project)

  3. I firmly believe that the ascendancy of HTML5 is going a long way toward making the id attribute less… necessary.

    However, if there’s only one of something, and I need the stylesheet to recognize it as a discrete thing, odds are that I’ll assign it an id. Don’t like it? Too bad.

  4. Hi JA –

    As always, thank you for a thought provoking post!

    A humble counterpoint:

    You use the word “page” an awful lot in this article. I think this underscores an assumption that a particular chunk of content is going to be presented in exactly one context. If you remove that assumption, the ID becomes extremely problematic for both CSS and JavaScript.

    This ID issue becomes fairly serious if content is being stored in a CMS as HTML. A single ID attribute – on, say, a sidebar entry entered by a contract employee who has no idea where the content will ultimately be presented – can break the JavaScript of an entire site.

    As content gets more and more chunkified and mashed up, the ID becomes less and less attractive. Now, if you were to concede that storing HTML in a CMS is a bad idea and that IDs would only be applied to the HTML *templates* into which the data would be poured, I’d be a lot more open to the idea ;)

    Bear in mind that I’m the first person to say that pretty much everything always depends. There is no one right way to do anything on the web (or anywhere in life?). That said, it’s extremely useful to have defaults from which you only deviate when the situation calls for it – i.e., conscious exceptions are fine; unconscious blunders suck.

    ASIDE:

    When I was in music school, the students often demanded that teachers define rules for them. This may sound surprising, but rules make it easier to progress because there is less to think about. Much to the students chagrin, however, the teachers religiously refused to define rules. Their rote response was that “there are no rules in music. There are only style practices.” In other words, if you want to sound like John Coltrane, there are certain things that yes, you HAVE to do. But those things were not rules *of music* – they are the rules of how play in the style of ‘trane.

    So, I think we’re talking about a “style practice” of the web. My advice to a n00b would be to default to not using IDs because they can get you in a surprising amount of trouble *but* to feel free to make a conscious exception at any time if you feel the situation calls for it.

    My $0.02

    :)

  5. Very well-articulated argument.

    Personally I’ve moved away from using IDs in CSS on larger sites where the CSS becomes more complex and modular, but on a smaller sites, particularly a simple one-page site, I do still use ID selectors. The suggestion of using attribute selectors like [id="bob"] (you don’t need the * before it AFAIK) hadn’t occurred to me before and seems like a good idea for tackling the specificity thing. But like you, I can’t recall ever having run into trouble with that.

    The point about “Any performance gains picked up by using id, is negated by adding any other selector to the left of that id” is, I feel, bogus anyway. I can’t think why you would need anything to the left of an ID selector – there should only be one matching element, so it doesn’t matter what’s above it in the tree.

    I think this mostly comes down to developer preference – do what works for you, just keep it standards-compliant.

    Pedantic point: You wouldn’t use querySelectorAll('#bob'), but rather querySelector('#bob') as you’re (hopefully) only expecting one node. But it seems like getElementById is way faster anyway.

  6. Saying “sometimes ID’s are misused so therefore ID’s should never be used” is as wrong as when people say, “tables shouldn’t be used for layout, therefore tables should never be used.”

    As with almost anything the question is not whether or not to use ID’s but when to properly use them. And John is right that it’s not just a styling hook. On my last big project I had a hard time convincing another employee that ID’s aren’t just classes that you can only do less with.

    BTW, “the HTML5 outlining approach” is messed up, or is at least seen by the vast majority of developers in a very, very wrong way. If people didn’t misunderstand proper header structure badly enough before HTML5 came along now they misunderstand it even more egregiously. HTML5 allows multiple H1’s for the rare instances where content from one site is ported over into a section within a completely different website; HTML5 simply allows you to then retain the H1 – H6 structure (not that there’s any hope that the people who developed that content will have *their* headers properly structured) of the ported over content, rather than trying to change its heading structure to work nicely with the heading structure of the surrounding content.

    BUT… developers in their wild enthusiasm to turn every header into an H1 (“hey, more Google juice! why relegate a header to the lowly level of an H2?”) took it as license to go H1-crazy with their own content. I can’t blame them too much because I think there’s some vagaries in the specs which I hope will eventually get smoothed out. Last I checked it was at least a tad better than before. But their wording seems to indicate the school of thought of, “Well, 99% of developers never knew what the heck to do with H2 – H6 tags so we might as well just let them make everything an H1.” It’s like reading a book or a magazine where every chapter or article heading (H2) and section heading (H3) carries equal weight with the title.

    • By: Finn
    • July 14th, 2013

    Ultimately, Angus’s point is we should understand the rules, practices and guidelines, and adopt these, or not, with an understanding of the benefits they bring, and the costs that come with them.

    One of the things I absolutely love about this article and that I’m telling all my junior developers all the time already. Lots of things today are taken for granted just because some experts strongly recommend it…

  7. […] In defense of the humble id attribute by John Allsopp […]

  8. What does “surface that content” mean? Otherwise a very cogent, level-headed article.

    I’ve not done any Web work in many years by now (IE7 was as yet unreleased the last time I touched CSS for anything other than laying out a yechnical manual), so the whole notion of IDs being something to avoid smacks of absurdity to me; It is therefore nice to know I’m not crazy. ;)

  9. I think the point here is that “ids are unique to a page” is a slight error, I would say “ids are unique within a page”. So an id no longer infers a single element, it refers to a number of occurrences across the website, which may all use the same style-sheet. Therefore, when I use an id-selector in my CSS, I might be re-using that rule 7,000 times.

    I know I’m arguing with you to agree with you in a way – but the arguments against id-selectors seem to be based on one-page-websites.

  10. […] John Allsopp, author, developer and conference organiser, has defended the “humble identity attribute”. […]

    • By: karl
    • July 24th, 2013

    “id out of fashion”… talk about cargo cult. :) hehe.

    What I usually reply.

    So simple, If you need to provide an anchor point in a document, use an id. I want to link to that section.

    If you want to augment the semantics of the document because the elements are not enough, use a class. You might want to parse it against certain categories. Do not forget rel too.

    CSS? Unrelated… id and class have not been created for CSS. CSS used them to target elements in the page. :)

    I’m with you on that. But I guess it is the same cargo cult about “semantics… I don’t care.” :) In the end, it doesn’t matter that much, some people will create nice shiny things, and some will create nice documents for a long time. :) The Web will survive.

    • By: Duncan
    • August 14th, 2013

    It’s nice to find a site where the quest for semantic mark-up lives on. In todays web development world, I wonder how many reactions are driven by the tools used to create.

    Performance issues surrounding CSS is entirely new to me!

    Just how much content is being pushed? How many style rules did you say? and what’s that normaliser, moderniser, JQuery, Ajax, widgets1..99 etc.

    ID’s are needed for the reasons mentioned by others.

    In ASP.NET, targeting ID’s is not always easy due to Naming Containers. The ID for a label used *for* input(‘type=text’) might be ct100_PageControl_panPerson_fsContact_grpPhone_lblFirstName. That’s just a label in various nested containers! Page – Panel – Fieldset – Group all with ID’s because of runat=”server” – all leads to lots of extra bytes sent.

    Where you create components like Panels etc, adding classes becomes essential. Your CSS can then target nested elements via additional class names, tag names, or these lovely jubbly new selectors.

    But then you remember that you still must support ie6. Nested classes start going haywire. panel.first.emphasis .content h2 {} targets your rules from other components. Ahhh!!!

    Listen to best practice, pick your patterns carefully, and get on with it.

    • By: Henri
    • August 20th, 2013

    I’ve come to the conclusion that most web standards, whether formal or informal, are actually bad – not because standardization itself is inherently bad, but because the process of establishing standards for the web has largely been hijacked by people who want to force their particular code design preferences on everybody. XHTML was the perfect example of this, where the XML-as-panacea people got together with the close-unnestable-tags people and the make-images-accessible-to-the-blind people and spat out a case sensitive markup language that crashed if you included a byte in the wrong character set. Or at how they’ve begun work on CSS3 even though CSS2 is not standardized and likely never will be, or how you’re now supposed to include “use strict” in your javascript files as a backwards-compatible way to specify more recent code, except that it isn’t backwards compatible at all. Then you have informal standards like OOCSS and JSLint that basically tell people to follow one person’s coding style. In the mean time there are still basic problems with these languages that no one is interested in fixing like proportional sizing in CSS. It’s just a (mis)feature of the language that everyone would rather work around so they can continue to argue about how to use selectors.

  11. Great article John.

    ID’s are a wonderful way to infer your intent as a content creator/developer. Since we try to use classes for re-usable styles.. the names tend to be more abstract. However ID’s and the role attribute are great for assigning intent.

    Also, ID’s are wonderful for Javascript. I use them to give scope a DOM section and sometimes a specific DOM element. Again, a well served purpose. var demElements = $("#idname").find("li") is a great friend of mine. :)

    However, I do find the idea of [id=idname] {css rules} very crafty, that still doesn’t get around the lack of re-usability. It’s still a one trick pony but if you get designs once and they are not modified throughout the site(or product) , then and ID might be fine for attaching a style that may never morph into a global design pattern. If you work on products/sites that are constantly “evolving”, then re-usable patterns is a solid way to ensure code that can be expanded in it’s use.

    Your H1 example is unfair because you should only be having one H1 per page anyhow. ;) At least, that’s how I roll. H2’s are a different story! I believe you should always be ready for a designer to add like-minded styles to the product, therefore limiting my code’s usefulness. Why not be re-usable because any css that’s used more than once on the site, adds value and deducts from the bandwidth deficit placed on your css files.
    I refer you to this little snippet (media object) that has massive value on the facebook site.
    The media object saves hundreds of lines of code
    Yes.. this belongs to Nicole Sullivan. :)

    That said.. I would say it’s not the end of the world if a person uses ID’s for their CSS.
    What matters to me, is the size of my CSS files, and re-usable is a friendly way of reducing that file size.

  12. I’d like to thank you for the efforts you have put in writing this
    blog. I’m hoping to check out the same high-grade content from you
    in the future as well. In fact, your creative
    writing abilities has motivated me to get my own site
    now ;)