HTML5, Older Browsers and the Shiv

Share this article

HTML5 introduced a few semantic elements that are not supported in older browsers. Some of these new elements are no different than generic block elements so they don’t pose any compatibility problems. All you need to ensure compatibility is to add a CSS rule to your website that causes the relevant elements to behave like block elements. But Internet Explorer versions 8 and under pose a challenge. Any element not in the official roster of elements cannot be styled with CSS. That means we cannot make then behave like block elements or give them any formatting. For example, the following code will not work.

<style>
section {display: block}
</style>
<section>This is on its own line.</section>
<section>This should appear on a separate line.</section>
But that’s not all. These new elements behave as if they don’t exist. For example, the following CSS won’t work, since the section element won’t match the universal selector.
<style>
body * span {color: red}
</style>
<body>
  <section>
    <span>This should be red, but won't be red in IE 8.</span>
  </section>
</body>
Fortunately for us, a workaround exists that allows Internet Explorer (IE) to recognize these new elements allowing them to be styled, and thus giving us full use of these new semantic tags. It’s a tool called HTML5Shiv. As noted on the linked Google page, “shiv” and “shim” are interchangeable terms in this context. But how did we go from IE not even acknowledging the existence of this element, to now being able to use it? The trick is that calling document.createElement("section") will suddenly cause IE to recognize the section element. No one knows why, but it works and you don’t even need to use the node returned by that function. But you need to make sure to call it early on in your website before any of those elements are used, otherwise it won’t work. You will need to call it for each and every new HTML5 elements like so:
"abbr article aside audio bdi canvas data datalist details figcaption figure "+
  "footer header hgroup main mark meter nav output progress section " +
  "summary template time video"
  .replace(/w+/g, function(a){ document.createElement(a) });
Notice we’re using the replace method of the string object to succinctly iterate over each contiguous length of characters matched by the regular expression and executing the callback function for each character block which in turn calls createElement. Here on in, we’ll call this method, “shivving the document”, so that the document can render the new HTML5 elements. Now our previous two HTML examples work. But that’s not all there is to it.

Pitfall 1: HTML5 and innerHTML

If HTML is being generated using innerHTML and it is called on a node not currently attached to a document (AKA an orphaned node), then it’s deja vu all over again. The following two examples will not render the section
element, even though it’s run on a document already shivved.
var n1 = document.getElementById("n1");
n1.parentNode.removeChild(n1);
n1.innerHTML = "<section>Sect 1</section>";  //won't work
var n2 = document.createElement("div");
n2.innerHTML = "<section>Sect 2</section>";  //won't work
In the second example above, if we append the node to the document first before calling innerHTML, then it will work:
var n2 = document.createElement("div");
document.body.appendChild(n2);
n2.innerHTML = "<section>Sect 2</section>";  //works
We can conclude that although we shivved the document earlier on, orphaned elements do not benefit from the shiv when calling innerHTML. What can we do? For starters, whenever we need to set innerHTML we should append it to the document first. An alternative is to first shiv the document property of the orphan before working with the orphan. First let’s put our shiv in its own function.
function iehtml5shiv(doc) {
  "abbr article aside audio bdi canvas data datalist details " +
    "figcaption figure footer header hgroup main mark meter nav " +
    "output progress section summary template time video"
    .replace(/w+/g, function(a){ doc.createElement(a) });
}
The next time we have an orphan element, we can do this:
var n1 = document.createElement("div");
iehtml5shiv(n1.document);
n1.innerHTML = "<section>Sect 1</section>";  //works
Notice how it’s just like shivving the document, but on the document property of the element. And notice we’re accessing document instead of ownerDocument. Both are different things as shown here:
alert(n1.document == document);  //false
alert(n1.ownerDocument == document);  //true
Now we have two methods to make sure our call to innerHTML
works when handling HTML5 elements.

Pitfall 2: cloneNode

It appears our cousin cloneNode is also susceptible to losing its shiv. Any HTML5 elements which are cloned, or have had their parents cloned, will lose their identity. Notice how the below element has colons in its nodeName, meaning it’s being confused for an element from another namespace.
var n2 = n1.cloneNode(true);
alert(n2.innerHTML);  //outputs: <:section>Sect 1</:section>
This happens even if the node was already attached to the document. There isn’t much we can do here except roll out your own implementation of cloneNode, which is trivial enough.

Pitfall 3: Printing

Whenever you print a webpage, IE appears to generate a new document before printing which means all the shiv workarounds are not preserved. There isn’t much you can do to mitigate this. The HTML5Shiv tool works around this by listening for the onbeforeprint event and replacing all the HTML5 elements on the page with normal elements and then doing the reverse on the onafterprint event. Thankfully, the HTML5Shiv tool does that nicely for us.

References

Frequently Asked Questions (FAQs) about HTML5, Older Browsers, and the Shiv

What is the purpose of HTML5 Shiv?

HTML5 Shiv is a JavaScript workaround, used to enable styling of HTML5 elements in versions of Internet Explorer prior to version 9. These older browsers do not recognize the new HTML5 elements like ‘section’, ‘article’, ‘header’, ‘footer’, etc. and as a result, they cannot style them. HTML5 Shiv allows these elements to be recognized and styled correctly, ensuring that your website looks consistent across all browsers.

How does HTML5 Shiv work?

HTML5 Shiv works by creating the new HTML5 elements in JavaScript, which makes them recognizable to Internet Explorer. Once these elements are recognized, they can be styled with CSS. This is a simple and effective way to ensure that your website looks the same in all browsers, regardless of their support for HTML5.

How do I use HTML5 Shiv in my website?

To use HTML5 Shiv, you need to include it in the head of your HTML document. It’s important to note that it should be included after any stylesheets, so that the styles can be applied to the newly created elements. Here’s an example of how to include it:

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles.css">
<script src="html5shiv.js"></script>
</head>
<body>
<!-- Your content here -->
</body>
</html>

Is HTML5 Shiv necessary for all websites?

HTML5 Shiv is necessary for websites that use HTML5 elements and need to support older versions of Internet Explorer. If your website doesn’t use these elements, or if you don’t need to support these older browsers, then you don’t need to use HTML5 Shiv.

What is the difference between HTML5 Shim and Shiv?

The terms “shim” and “shiv” are often used interchangeably, but they actually refer to two different things. A shim is a library that brings a new API to an older environment, using only the means of that environment. A shiv, on the other hand, is a piece of code that enables the use of new elements in older environments that do not natively support them. In the context of HTML5, the HTML5 Shiv is a script that enables the use of HTML5 sectioning elements in legacy Internet Explorer.

Are there any alternatives to HTML5 Shiv?

Yes, there are several alternatives to HTML5 Shiv, including Modernizr, which is a JavaScript library that detects HTML5 and CSS3 features in the user’s browser. Another alternative is to use a polyfill, which is a piece of code that provides the technology that you, the developer, expect the browser to provide natively.

Does HTML5 Shiv affect website performance?

HTML5 Shiv is a very small script, so it should not have a significant impact on your website’s performance. However, as with any additional resource, it’s important to ensure that it’s only loaded when necessary, to avoid unnecessary overhead.

Can I use HTML5 Shiv with other JavaScript libraries?

Yes, HTML5 Shiv can be used with any JavaScript library. It does not conflict with other libraries, and it does not depend on any other libraries.

Is HTML5 Shiv still necessary today?

The necessity of HTML5 Shiv depends on your audience. If you need to support older versions of Internet Explorer, then yes, you will still need to use HTML5 Shiv. However, if your audience primarily uses modern browsers that support HTML5, then you may not need to use it.

Where can I download HTML5 Shiv?

HTML5 Shiv can be downloaded from the official GitHub repository. It’s also included in many popular HTML5 boilerplates and templates, so you may already have it in your project.

Dmitri LauDmitri Lau
View Author

Dmitri Lau is a freelance Ajax developer with a penchant for statistical analysis. When not improving a meta template engine's relative response yield, yawning uninterruptedly every night has become a norm which he hopes will soon be over when his Hong Kong based startup picks up.

HTML5 Dev Center
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week