Supporting IE8 in 2014

Whilst we all enjoy the pace of modern browser development, with new standards often in users' hands within months rather than years, unfortunately IE8 is still around in significant numbers. It was a huge step forward from IE7 — we could finally count on ordinary CSS 2.1 stuff to render reliably — but here in 2014 it has a few obvious shortcomings that will leave it struggling with modern front-end code.

The project I spend most of my time on at the moment suffers from this — IE6 and IE7 users are long gone1, but a sizeable number of users are still running IE8, and that number isn't going down very slowly, despite Windows XP support ending.

Browser support isn't a binary thing, though — whilst IE8 won't provide as good an experience as IE11 or Chrome, we can still do some things to get it to an acceptable level, without compromising on use of new technology.

HTML5 elements

Without help, IE8 won't recognise new HTML5 elements like <section> and won't apply styles to them or their descendants. The long-established solution is the HTML5 Shiv, which inserts an instance of each new element to the DOM, triggering IE8 to recognise it. I use it a little differently than the documentation suggests, inlining the script to save the extra HTTP request2:

<!--HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed-->
<!-- [if lt IE 9]>
    <script>!function(a,b){...</script>
<![endif]-->

(You'll need the latest minified version of the script to insert there3.)

Media Queries

With media queries at the core of how websites are being built in 2014, they are arguably the most serious missing feature in IE8, especially when you use them the mobile-first way (which you should). Respond.js is a good way around this, but personally I prefer to avoid throwing more JavaScript at an old browser on an old computer.

grunt-stripmq is a Grunt plugin that parses a stylesheet and strips out the media queries based on preset values for media type, width, height, orientation etc, leaving you with just the rules that would apply to a browser with those properties (in other words, it's doing a similar job to Respond.js, but as a build step rather than on the client). To provide a stylesheet for IE8, I set it up like this in my grunt.initConfig:

stripmq: {
    options: {
        width: 1000,
        type: "all"
    },
    all: {
        files: {
            "css/oldie.css": ["css/style.css"]
        }
    }
}

Then, I reference that stylesheet in a conditional comment for IE8 and older:

<!-- [if (gte IE 9)|(IEMobile)]><!-->
    <link rel="stylesheet" href="/css/styles.css" />
<!--<![endif]--> 
<!-- [if (lte IE 8)&(!IEMobile)]>
    <link rel="stylesheet" href="/css/oldie.css" />
<![endif]-->

(The IEMobile bits stop the IE8 stylesheet being served to IE on Windows Phone 7, which will do better with the regular mobile-first stylesheet even though it doesn't support media queries.)

SVG

SVG has really started to gain traction in the last year or so, and with good reason — as raster images become increasingly troublesome on a web with almost infinite viewport size and pixel density combinations, SVG is a better option for almost any image except a photo.

Of course, IE8 doesn't support SVG, so you'll need to provide a PNG fallback.

Fonts

Microsoft, who have always worked hard on typography-related stuff, actually beat the other browser vendors to @font-face support by many years, albeit with the proprietary EOT format until much more recently. The excellent Font Squirrel webfont generator will take care of producing the EOT version for you, and your @font-face declarations will look something like this:

@font-face {
    font-family: 'Wingdings';
    src: url('../fonts/wingdings.eot');
    src: url('../fonts/wingdings.eot?#iefix') format('embedded-opentype'),
         url('../fonts/wingdings.woff') format('woff'),
         url('../fonts/wingdings.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}

JavaScript

If you're using jQuery in your project, this part is going to be straightforward. A lot of people are questioning how necessary jQuery is in this new age of querySelectorAll and CSS transitions, but for me its main strength isn't shorthands, but cross-browser support.

The jQuery 1.x branch still supports IE6--8, and is API compatible with the leaner 2.x branch (which works in modern browsers only). Some more conditional comments4 will ensure we serve the best version for every browser (this goes just before the `` closing tag for best performance):

<!-- [if gte IE 9]><!-->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--<![endif]-->
<!-- [if lte IE 8]>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<![endif]-->
<script src="/js/main.js"></script>

If you're not using jQuery but writing plain JS, don't despair — IE8's JavaScript support isn't terrible:

  • querySelector and querySelectorAll are supported, although weirdly getElementsByClassName isn't
  • XMLHttpRequest is supported (although many newer XHR features are missing)
  • localStorage is supported
  • addEventListener is missing, but you can use the similar (proprietary) attachEvent instead without much trouble

Most of the new shiny HTML5 features like <canvas> and AppCache aren't there, but the ones listed above are enough for most regular DOM scripting.

Alternatively, think about whether your site works without the JavaScript (ideally it should). If it does, then you have the option of just not running it on IE8 and below. The BBC's "cut the mustard" test works brilliantly for this, by doing a quick feature test to decide whether the browser is modern enough to run the script:

if ('querySelector' in document &&
    'addEventListener' in window &&
    'localStorage' in window) {
    var s = document.createElement('script');
    s.src = '/js/main.js';
    document.body.appendChild(s);
}

(As well as IE8 and below, this test will also save the script from being downloaded and executed on a lot of feature phones and lower end smartphones where it would do more harm than good.)

Testing

Since, as a web developer, the chances of IE8 being on your main computer are basically zero, you'll need to set something up to test your work. Browser modes in IE9--11 (accessible via the developer tools) are a useful way to test often as you work, but they aren't a perfect representation, so a real running instance is essential. Browserstack is great for this, but there's also a good chance that someone you know has an old Windows XP laptop gathering dust in a cupboard — take it off their hands and use it as a test device.

What about IE6 and IE7?

Unlike IE8, which has a solid baseline of CSS 2.1 support, IE6 and IE7 are going to struggle even with relatively simple front-ends. Providing workarounds to give users on these browsers a recognisable version of the experience you designed is going to be very costly (if it's even possible), so it might be worth entertaining the idea of just serving them the HTML with a simple, type-friendly stylesheet.


  1. The site's users are in the UK, Europe and North America. I know, though, that in the rest of the world, particularly Asia and Africa, it's a different story — IE6 is very much alive
  2. Aside from the extra few kilobytes in the <head>, there's no performance hit for modern browsers, as they'll just see a comment and won't actually parse the JavaScript. 
  3. There's another version that also does the same job for printing, if that's required in your case. 
  4. What, more conditional comments? Yes, I know they're very un-standards, but next to the alternatives — UA sniffing and weird hacks born of implementation bugs — they're the least inelegant.