A Close Shiv

written by jonathantneal on June 19, 2012 in JavaScript with 3 comments

As some history books of the www read, I am more than a little obsessed with the legacy of HTML5, particularly with the legacy browsers. The fixation runs deep, and I find my lamentations becoming songs about Internet Explorer 6. Most of my real contributions to HTML5 “legacy” have landed themselves in a script known as HTML5Shiv, maintained by Alexander Farkas, John-David Dalton, and myself.

A shiv works by running the createElement method on a document, which, in IE, triggers support for the element in the document tree.

document.body.innerHTML = 'Mark <mark>my words</mark>.'; // <mark> fails to render correctly.
document.createElement('mark'); // shivs <mark>.
document.body.innerHTML = 'Mark <mark>my words</mark>.'; // <mark> renders correctly.

Of course, not all HTML is added directly to the document. Many times, HTML is added to detached elements, which also must be shivved.

document.createElement('mark'); // shivs <mark>

var p = document.createElement('p');
p.innerHTML = 'Mark <mark>my words</mark>.'; // <mark> fails to render correctly.
p.document.createElement('mark'); // shivs <mark> on <p>'s internal document.
p.innerHTML = 'Mark <mark>my words</mark>.'; // <mark> renders correctly.

The work adds up, and HTML5Shiv handles all of this. HTML5Shiv enables Internet Explorer to properly render about 23 HTML5 sectioning elements, providing default styles for them and ensuring that they print successfully.

HTML5Shiv has been integrated into almost every CMS and JavaScript DOM library out there. That’s not surprising, considering that 30% of the popular web is using HTML5 despite Internet Explorer 6, 7, and 8 completely disregarding HTML5 elements. The situation is compounded by IE’s 20%-50% browser market share, depending upon who is asked. These statistics do not change one imperative reality: HTML5Shiv is a surrogate, a crutch, destined to wither away with each passing of Internet Explorer, until the day it accompanies IE8 into the sunset, and flights of angels sing them to their rest.

For developers, desperate to drop any and all of these oldies, the time ticks too slowly.  But now, Google,  Facebook, and even Microsoft have made heavy-handed moves to raise the bar of browser expectations. They are dropping support for IE6 and IE7, and leaving IE8 as the new low in browser compatibility.  With this change, the browser compatibility clock is moved forward 8 years.

In a world where IE6 and IE7 step aside, IE8 would then offer new approaches to the same HTML5 incompatibilities. One approach would be to drop the list of sectioning elements in lieu of a defineProperty listener, hijacking the innerHTML setter, and shivving support for new elements responsively.

document.documentMode == 8 && this.Element && (function (document, innerHTMLPropertyDescriptor) {
	Object.defineProperty(Element.prototype, 'innerHTML', {
		set: function (content) {
			var cite = this;

			innerHTMLPropertyDescriptor.set.call(cite, content.replace(/<(\w+)/g, function (m, m1) {
				cite.document.createElement(m1);

				return m;
			}));
		}
	});

	document.attachEvent('onreadystatechange', function () {
		document.body && (document.body.innerHTML = document.body.innerHTML);
	});
})(document, Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML'));

There are issues to consider, like redeclaring the entire body of HTML (oh, you noticed that). Also, the cloneNode method would still break HTML5 elements, although there may be a solution to that as well, using protyping.

document.documentMode == 8 && this.Element && (Element.prototype.cloneNode = function (deep) {
	var cite = this, element = document.createElement(cite.parentNode.nodeName);

	element.innerHTML = deep ? cite.outerHTML : cite.outerHTML.replace(/<(\w+)([^>]*)>[\W\w]*$/, '<$1$2></$1>');

	return element.removeChild(element.firstChild);
});

This back and forth could go on, further feeding my fixation, but the point is clear. The higher the browser bar is raised, the better the band-aids get. Now, if you don’t mind, I’ll be writing a program. See you next time.