Mathias Bynens

The id attribute got more classy in HTML5

Published · tagged with CSS, HTML, Unicode

One of the more subtle yet awesome changes that HTML5 brings, applies to the id attribute. I already tweeted about this a few months ago, but I think this is interesting enough to write about in more than 140 characters.

How id differs in between HTML 4.01 and HTML5

The HTML 4.01 spec states that ID tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens (-), underscores (_), colons (:), and periods (.). For the class attribute, there is no such limitation. Classnames can contain any character, and they don’t have to start with a letter to be valid.

HTML5 gets rid of the additional restrictions on the id attribute. The only requirements left — apart from being unique in the document — are that the value must contain at least one character (can’t be empty), and that it can’t contain any space characters.

This means the rules that apply to values of class and id attributes are now very similar in HTML5.

Err, what?

Although that probably sounds boring, this actually is pretty cool. In HTML 4.01, the following code is perfectly valid:

<p class="#">Foo.
<p class="##">Bar.
<p class="♥">Baz.
<p class="©">Inga.
<p class="{}">Lorem.
<p class="“‘’”">Ipsum.
<p class="⌘⌥">Dolor.
<p class="{}">Sit.
<p class="[attr=value]">Amet.

Heck, you could even use a brainfuck program as a classname:

<p class="++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.">Hello world!

I’ve put up a demo page with some other examples, but I’m sure you can think of more. After all, the possibilities are endless :)

So what’s new?

In HTML5, you can take all of these groovy classnames and use them as values for id attributes. Yes, HTML5 is that awesome.

<p id="#">Foo.
<p id="##">Bar.
<p id="♥">Baz.
<p id="©">Inga.
<p id="{}">Lorem.
<p id="“‘’”">Ipsum.
<p id="⌘⌥">Dolor.
<p id="{}">Sit.
<p id="[attr=value]">Amet.
<p id="++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.">Hello world!

…you get the idea. I remade the same demo page as before to use ids instead of classes.

How to escape any character in CSS

Writing CSS for this markup is tricky. For example, you can’t just use ## { color: #f00; } to target the element with id="#". Instead, you’ll have to escape the weird characters (in this case, the second #). Doing so will cancel the meaning of special CSS characters and allows you to refer to characters you cannot easily type out, like crazy Unicode symbols. It gets even trickier if you need to use these escaped CSS selectors in JavaScript as well.

That’s why I’ve written a separate blog post explaining how to escape any character in CSS, and how to use escaped CSS selectors in JavaScript.

About me

Hi there! I’m Mathias. I work on Chrome at Google. HTML, CSS, JavaScript, Unicode, performance, and security get me excited. Follow me on Twitter, Bluesky, and GitHub.

Comments

Glenn Glerum wrote on :

Mathias, is this backwards compatible? Or do older browsers just ignore `ID`s like that? And what does it do for semantics? It’s fun when you can use a `class` like `"i-just-♥-this-sub-navigation„ø¤º°¨¨°º¤ø ¸„ø¤º°¨¨°º¤ø"` but would you put it to practice?

seutje wrote on :

The night after I noticed this in the HTML5 spec was my worst night ever. Never before have I had such violent nightmares about IRC support and people doing fucked up shit, wondering why it doesn’t work entirely as expected… :(

wrote on :

[**Glenn:**](#comment-1) All tests on both demo pages pass in every A-grade browser, including IE6. So yeah, I’d say it’s backwards compatible.

wrote on :

I’m getting a lot of “Who would ever use this?” and “Any *real* use case here?” responses, so it seems a little more explanation is needed. While some of my examples will most likely never be used in production, the fact that HTML5 now allows `ID`s to contain just about any character (as was already the case for the `class` attribute in HTML 4.01) is definitely an improvement. As some people on [Hacker News](http://news.ycombinator.com/item?id=1507403) have pointed out, this is pretty damn useful: * An `` element with `name="items[0][name]"` can now finally have an `id` matching the `name` attribute. This would be invalid HTML 4.01, but valid HTML5: `` * It might be useful for programmers in other languages, so they don’t have to either come up with English names, less descriptive names (`"id1"`), transliterating words, or replacing letters with ‘similar’ ones (‘O’ or ‘OE’ for ‘Ø’).

Kroc Camen wrote on :

[**seutje:**](#comment-2) This is just standardizing what all browsers already support. Developers have been able to do this all along anyway. Yes, you can shoot yourself in the foot with it, but being able to use accented characters in `class` and `id` names is a definite plus and much welcomed.

seutje wrote on :

[**Kroc Camen:**](#comment-5) I know, I’ve already run into this nightmare as someone was using underscores in his class names and wasn’t escaping these in the CSS, which caused IE6 to completely ignore it, while all other browsers gladly accept it unescaped: IE6 will show all green, all other browsers will show all red. **Edit:** Actually, only the unescaped `_foo` is a problem, not `foo_` or `foo_bar`. Here’s a better test case: Nice catch, [Nicolas Gallagher](http://nicolasgallagher.com/)!

Albert wrote on :

Marvelous! Random usage off the top of my head: links, `#456bereast`, `#321contact`, `#24ways`, etc. Nice, nice, nice!

David Bishop wrote on :

I don’t see how this makes HTML5 more classy. This just seems… unnecessary at best. Sometimes restrictions such as what exists in the HTML 4.01 spec are necessary to keep developers from doing crazy stuff. I’m just not sure why most developers would need this; I’m not sure the minor gains are worth the possible headaches that can now be made by poor programmers.

wrote on :

[**Weston:**](#comment-8) Yes, this works in [XHTML5](https://mathiasbynens.be/notes/xhtml5 "The XML serialization of HTML5, aka XHTML5") as well. [**David:**](#comment-9) The “`class`y” part is a pun, since the `id` attribute restrictions in HTML5 are very similar to those of the `class` attribute (in HTML4+). HTML5 gives developers more freedom to choose which characters they want to use for `ID`s. I’m not sure why you think this is a bad thing. To me, it’s definitely an improvement.

Vic Shoup wrote on :

[**David Bishop:**](#comment-9) Agreed. Sounds really cool with all the flexibility until you start accounting for all the other things it can impact… Then you have to go in and do those things differently so they behave normally under HTML 5.

Weston Ruter wrote on :

Fascinating. If this works in XHTML5 as well, isn’t this a direct violation of the XML spec? I guess not if DTDs aren’t used anyway and so the `id` attributes aren’t of the `ID` type—so they don’t have to be [XML `Name`s](https://www.w3.org/TR/REC-xml/#NT-Name).

wrote on :

[**Weston:**](#comment-12) To be honest, I wouldn’t know if this is a violation of the XML spec or not. I’m not much of an XML guy. I just recreated [the entire testcase in XHTML5](/demo/xhtml5-id) (I had only tested a few `ID`s in XML before) and it turns out that in XML mode, there are three invalid `ID` values on my demo pages: * `id="

"` * `id="<><<<>><>"` * `id="++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."` I had to remove these or the page wouldn’t be rendered. So, in XHTML5, `ID`s cannot contain an unescaped less-than sign (`<`). Other than that, everything seems to work fine. Use of the greater-than sign (`>`) presents no problem whatsoever, and I can see why. Note that it would be possible to use these three `ID`s in XHTML by wrapping the contents of the `

This paragraph gets a lime background. ``` Any value for the HTML `id` attribute can be represented in CSS (or in selectors in JavaScript/jQuery). Check out the the tool I link to in this post.

tomByrer wrote on :

Doesn't seem that period is allowed for IDs, at least where CSS is concerned: http://jsbin.com/mimey/1/edit :(

wrote on :

[**tomByrer:**](#comment-32) You just have to escape it. Read the last paragraph in this post. > […] That’s why I’ve written a separate blog post explaining [*how to escape any character in CSS*, and how to use escaped CSS selectors in JavaScript](/notes/css-escapes).

José A M Pacheco wrote on :

I made a page with only the following: ``` ``` …and before the ``: ``` ``` Tested in Chrome 36, IE8, IE11, and the latest version of Firefox, and it worked in all of them. Does this make `document.getElementById` obsolete?

wrote on :

[**José:**](#comment-34) See [_Named access on the `Window` object_](https://html.spec.whatwg.org/multipage/browsers.html#named-access-on-the-window-object) in the HTML Standard.

Leave a comment

Comment on “The id attribute got more classy in HTML5”

Your input will be parsed as Markdown.