HTML5 elements in Internet Explorer without JavaScript
Written on the 23rd of November 2010

TOO LONG; DIDN'T READ
Use HTML5 elements in Internet Explorer 8 without JavaScript by using XHTML namespacing.
This method validates. See this example.
Solution Example XHTML5

When using HTML5 for your website, you'll soon notice that Internet Explorer 8 refuses to acknowledge, and subsequently style, all those newfangled HTML5 elements. They simply collapse into nothingness, as if they never existed in the first place. Depending on how complicated your markup is and how many HTML5 elements you've used, this makes your website full of semantic hotness pretty much look like dog poo in IE.

Delen   Tweeten

Huh? Section element? I don't see no stinkin' section element. You must be mistaken, pal. What? No, I don't believe in them. Get outta here. I'm serious, pal. Get lost, or I'll sack my quirks mode on you.

John Resig drummed up a clever little solution that uses a tiny piece of Javascript to force Internet Explorer to accept those new elements:

javascript:
var a = ['section', 'article', 'nav', 'header', 'footer', ...];

for (var i = 0, j = a.length; i < j; i++) {
document.createElement(a[i]);
}

Unfortunately, it doesn't work when Javascript is turned off.

And of course, after putting a new website live, the client calls up and tells you one of their "clever" system administrators has just turned off Javascript on every single workstation due to "safety concerns" and refuses to turn it back on.

So you look for a different solution. You can find a few, none of them particularly pleasant or useful. The WhatWG group advises the following:

  1. Know what the DOM looks like and target other elements for styling.
  2. Use the universal selector (*) to target the right element.
  3. Use [the] noscript [element].

Yes, really good options. Actually, no. They're not.

First, targeting other elements isn't exactly feasible. If it was that simple, we would've done that already. In order to apply the styles to a parent or child element, we'd need something above or below that's basically free of the styles we want to apply. This means we've got to wrap them all up in <div> elements, since the original ones collapse. Funny, since avoiding a distasteful tag-soup of semantically meaningless <div> elements is one of the reasons for using HTML5 in the first place.

Second, using the universal selector is not only whoefully inefficient, but it has the potential of making a mess of your CSS; you'd have to keep careful watch and undo the undo's its making on elements that follow the same patterns. This can get rather messy, rather quickly, especially if you try to avoid using too much classnames or ids:

css:
body > footer > p {
font-style: italic;
}

body > * > p {
font-style: italic;
} /* for IE */

body > ... > p {
font-style: normal;
} /* undo above in non-footer elements */

And third, the noscript element is absolutely useless in this case. We know the user doesn't have Javascript if the elements don't display properly. You can wrap the styles up in a noscript element, but Internet Explorer still won't apply them to the elements it keeps forcefully ignoring. The best you can do is try to not make too big of a mess when targeting the parent or child elements, but then, you'd be better off just applying it permanently for everyone. Easier in maintenance that way.

A guy called Fakedarren cobbled together a different solution, which shows a creative, if messy use of conditional comment tags:

html:
<!--[if lt IE 9]><div class="article"><![endif]-->
<!--[if IE 9]><article class="article"><![endif]-->
<!--[if !IE]><!--><article class="article"><!--<![endif]-->
...
<!--[if lt IE 9]></div><![endif]-->
<!--[if IE 9]></article><![endif]-->
<!--[if !IE]><!--></article><!--<![endif]-->

And it does work. But, and be honest here, wouldn't you rather run around nude at the workplace, right in front of your colleagues and boss, before you'd start using something like this for every single HTML5 element employed by your website? It would make your markup a horrifying mess.

Fortunately, you can keep your pants on. There's a solution, and it's not too unpretty.

The solution

The solution is actually pretty simple; put the new HTML5 elements in their own namespace. By doing so, Internet Explorer skips checking (and collapsing) the new elements and they display just fine. It's the same method as styling an XML document with CSS and Internet Explorer displays that just fine, too.

html:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:html5="http://www.w3.org/1999/xhtml">
<body>
<html5:section>...</html5:section>
</body>
</html>

And target the element by either the namespace or a simple id or class:

css:
html5\:section, #element-id, .element-class {
...
}

Note:   You need to declare the HTML5 namespace globally. You can not declare it locally on an <article> element, for example.

Also, as far as I'm aware, this solution also works quite beautifully for IE print styles, while the javascript solution doesn't.

The example

Standalone XHTML5 example (validates)
Standalone HTML5 example (works, but doesn't validate)

Because the last element is in its own namespace, Internet Explorer applies the CSS just fine. See the examples for a simple testcase and poke around in the source a bit, if you're interested.

Keep in mind that the colon in the CSS needs to be escaped with a backslash \ to avoid collision with pseudo-classes like :hover and such. However, aside from setting display: block, you don't need to use the namespace method -- id's and classes work just fine.

Also, HTML5 that's used in this way officially doesn't support namespaces. As you probably realize, this means that the validator will throw errors at your face when you feed it your website. A case could be made that validation doesn't matter, only results, but you'll have to decide that on your own.

However, if you're absolutely set on passing the validator, then that's no problem at all. Simply use XHTML5 instead of HTML5. Never heard of it? Don't feel bad. According to Anne van Kesteren, a lot of people don't realize that HTML5 also extends XHTML 1.0; it's just a case of writing your HTML5 in a XML-conforming manner.

Using XHTML5

To be perfectly clear, you don't have to use the XHTML5 syntax for this method to work. However, using this method in HTML5 markup doesn't validate, while using it in XHTML5 markup does validate. It's up to you to choose which markup you prefer; both have positives and negatives.

Using XHTML5 means that you've still got the new semantic hotness that is HTML5, including the new abilities like the <video> & <audio> elements and geolocation, but you also have the upside (or downside, depending on your point of view) of extremely strict parsing. Either way, the XHTML5 specification includes namespaces and that means that it'll validate just fine.

In order to use XHTML5 you need to take care of a few things. On the server side you'll have to follow the same steps as if you were using XHTML 1.0:

  1. Configure the server to send application/xhtml+xml to modern browsers and text/html to Internet Explorer, even though it's considered harmful by some. Internet Explorer won't display your page otherwise, instead, it would show a file dialog.
  2. Use the XML declaration: <?xml version="1.0" encoding="utf-8"?> and make sure it'll be sent to all browsers, again excluding Internet Explorer. Otherwise, IE6 can switch to quirks mode. Unless, of course, your client doesn't care about IE6. Which he shouldn't, seeing as it's over a staggering nine years old.

And on the document side it's a little different:

  1. Use the DOCTYPE; the first word must be in capitals and it has to go after the XML declaration: <!DOCTYPE html>
  2. Define the XHTML namespace and the XHTML5 namespace in your html element: xmlns="http://www.w3.org/1999/xhtml" xmlns:html5="http://www.w3.org/1999/xhtml" And yes, they are the same. The browser only needs to be tricked in believing that the namespaces contain different content.
  3. Use the HTML5 prefix with HTML5 elements: <html5:section>...</html5:section>
  4. Use the HTML5 prefix in the CSS for your HTML5 elements: html5\:section { ... } Make sure you escape the colons in your CSS with a backslash!
  5. Use regular ids and classes for normal styling, if you so prefer.
  6. Make sure there are no errors in your XHTML, or you'll see no website at all.

When you're done with that, it will validate properly, as you can see by validating this page in either the W3C validator or the .nu validator.

Have fun with (X)HTML5.