Progressive enhancement

Let me begin by putting my cards firmly on the table: if you don't build websites with a progressive enhancement mindset then you don't get the web. Progressive enhancement is how the web is built, and fundamentally ignoring the founding principles of the web serves only to shut out potential users and customers.

But what does progressive enhancement really mean? In this article I aim to dispel a few myths, set out a framework for thinking about progressive enhancement, and give some practical pointers on making your websites better.

Progressive enhancement: it's in the web's DNA

In the beginning

Everyone remembers sitting by the fireside and hearing the folk tales surrounding the birth of the web.

What was it like before the web, dad?

Well, child, the earth was dark and formless and everyone shuffled around in perpetual fear and sadness. Then out of the gloom strode a man named Tim...

Sir Berners-Lee and the other architects of the web were clear from the very beginning that accessibility of information to all was a primary objective of the web. It's baked right into the principles of the World Wide Web Consortium, so it's as close to the core of the web as it's possible to get.

Backwards compatibility

Those early websites - even the very first website - were just HTML. Plain old HTML, just structured content accessible to any software that understood its simple syntax. The fact that you can still read those documents using a modern browser more than twenty years later is a testament to the far-reaching vision of those early pioneers. How many other document formats can you still open after a couple of decades using modern software? Just try it with any old word processing file or Photoshop document.

The notion of backwards compatibility has been another core principle for the evolution in HTML over the years. The most obvious recent example are the set of new HTML input types: 'range' and 'email', for example. If a browser doesn't understand these input types to provide a specific UI for them it falls back to providing a vanilla-flavoured - but perfectly usable - standard text input.

Users with those older browsers miss out on baked-in client-side validation of values, but they can still interact with the form. You are validating user input on the server side, aren't you?

You can apply that same fundamental principle of backwards and forwards compatibility to your pages, by ensuring you build from a base of standard markup then enhance with CSS and JavaScript. That is progressive enhancement.

Progressive enhancement isn't against JavaScript

Progressive enhancement says "let's start with something robust, basic and universally-accessible, then enhance it". How far can you enhance it? As far as you like, then a bit more if you're feeling crazy. There is nothing in a progressive enhancement approach which stops you going wild with advanced JavaScript - as long as the thing you are enhancing will do the job even without the enhancements.

You've seen those cheap cars with ridiculous body kits, right? I bet you look at those and think "yeah, but it's still just a Corsa underneath". That, right there, is progressive enhancement. Take something basic, robust and usable, then enhance it as far as you want to go.

Progressive enhancement isn't hard

Web development is much more complicated than it used to be. Clients are becoming more demanding as they see their competitors sites full of whizz-bang features, and they want you to build the same for them by yesterday. I get it, I have the same pressures.

Some people that say accessibility is hard, or writing high-performance sites is hard, or responsive design is hard. That is all true, if you try to bite off everything at once. I believe if you're willing to put in the effort to learn the basics then you'll have a great foundation to build upon. Learning how to write robust, standard, semantic markup is the foundation of good web development.

Progressive enhancement is not something that comes to many people naturally, but there's no reason the skills it requires can't be learned and put into practice. We are extremely lucky to be working in an industry which shares so much knowledge so freely.

But where do we start? We start with understanding the Progressive Enhancement Continuum. But first, let's deal with graceful degradation.

Graceful degradation

Graceful degradation is the inverse of progressive enhancement. Rather than developing a universally-usable foundation and enhancing for modern browsers, a graceful degradation approach will start with the bells-and-whistles version of a page and then attempts to make the page work in older browsers.

There's been quite a bit of talk over the last couple of years about how graceful degradation is a Bad Thing and progressive enhancement is Here To Save Us All. I agree, but the truth isn't quite as simple as that. It's important to get down to specifics, so some examples are needed.

Here's an example of the bad kind of graceful degradation. You want to provide drag-and-drop file-upload functionality in your form, and you find a simple jQuery plugin called 'Uploadify' to do it. But the plugin doesn't work in IE8 and your boss says you need to support IE8. So here's what you do (this is pseudo-code, but you get the idea):

<div id="upload">
</div>

<script type="text/javascript">
$(function(){
    $('#upload').uploadify();
});

if (document.browser == 'IE8') {
    $('#upload').html('<input type="file" name="upload" />');
}
</script>

This provides upload support in IE8, but only if the script works. If you have a syntax error, or the script file fails to load (especially a problem if it's on a 3rd party domain such as a CDN) or the user has JavaScript disabled then that file upload field isn't available at all. All the client gets by default is a <div>, and what use is that?

The problem here is the lowest level content you're providing isn't a standard HTML input field, it's just HTML. Here's what you could do to rewrite this in a progressive enhancement way:

<div id="upload">
  <input type="file" name="upload" />
</div>

<script type="text/javascript">
$(function(){
    if (document.browser != 'IE8') { // this might not even be needed!
        $('#upload').uploadify();
    }
});
</script>

In this example the HTML served to the browser contains everything the browser needs to offer upload functionality to the user. Then you use your plugin to enhance that functionality.

So what about the good type of graceful degradation? Here's an example:

<input type="range" />

Yep, that's it. In a modern browser the user will see a slider, in browsers that don't support HTML input types they'll see a text input.

At this point you can then decide if a plain old text input will do, or enhance (there's that word again) it with a smidge of JavaScript. That process of "enhancing an old browser so it supports modern stuff" is what polyfills are designed for. The Can I Use website is a great resource for browser support and polyfills.

When JavaScript goes bad

I've heard a few developers say things like "most people don't disable JavaScript, so we can rely on it working". Let's look at a few reasons why JavaScript, or a crucial JavaScript file, might not be work on your pages:

  • The user may have disabled JavaScript
  • Network administrators may have disabled JavaScript, or blocked .js files
  • Your page may contain an invalid URL for a JavaScript file
  • Your web server may not serve JavaScript with the correct MIME type, meaning it won't be parsed correctly
  • A DNS error may mean your CDN or static resources domain is not available
  • Your CDN or static resources domain may be responding very slowly
  • A JavaScript file may not be readable, e.g. locked by another process
  • There may have been an error that means the JavaScript file is empty
  • There may be a syntax error that stops your file being parsed correctly
  • There may be something not supported by the browser which stops the script parsing (e.g. console.log)
  • The user may start to interact with your page before a JavaScript file has been downloaded, or before your event handlers have been attached to elements

How likely are any of these errors? It would be a very poor website that saw any of these errors regularly, but they are certainly all possible. Part of our responsibility as web developers is to ensure we build robust systems, so mitigating against errors like these is very important.

Progressive enhancement allows us to do that. Approaching the development of a page as standard, robust HTML first, then enhancing from there means that if any of your enhancements fail your users still have a usable page.

A continuum of support

This approach means a continuum of browser support, not a binary choice between graceful degradation and progressive enhancement. This diagram hopefully illustrates this continuum.

Progressive enhancement continuum

This shows the range of browsers that we could potentially have visit our sites right now; older ones to the left and newer ones to the right. The red line shows the "optimisation line" where we have decided to start optimising the users' experience. Browsers older than this can expect to get a basic – but still usable – website, browsers newer than this will get whatever bells and whistles you've built.

This red line is where you'd use polyfills. For example, on a recent website I needed to use an <input type="range"> element, which is not supported in older IE. Rather than use a jQuery plugin to provide that functionality I coded a standard HTML5 <input type="range"> element, knowing that newer browsers support it.

I then decided where my optimisation line should be and added polyfills to "fix" IE 9 and 8 so they support <input type="range">. Conditional comments allowed me to load those polyfills just for the browsers that need it; all the "evergreen" browsers (Chrome, Firefox etc) get the standard HTML5 element - and eventually older versions of IE will die out so these polyfills will get used less and less as time goes on.

Why did I choose this point to add some polyfills? Because for the project I was working on the number of IE8 users was deemed big enough to warrant the effort. People still on IE7 (and yes, there are still some of those) are the ones for whom just the basic HTML pages will work. Anyone above that gets some form of enhancement.

This idea of the web being a continuum is not my idea, the very clever Jeremy Keith thought of it first.

The rubbery road

Do you add alt attributes to images? Yes? Why? Because you know that in some situations - images are disabled, or the user is using assistive technologies such as a screen reader - it makes the experience of using the page better. In days gone past we used to proudly display 'Bobby Approved' logos on our sites to prove that we had constructed them well, and alt attributes were one of the checks that Bobby used to do. For most of us, even those too young to remember the beginnings of the web standards movement, alt attributes are still just something you do.

Adding alt attributes is something we do almost without thinking about it because we know it's the right thing to do. It's that same mindset which underpins progressive enhancement. There are a few other areas we can pay attention to, and with a bit of practice it will become second nature to think progressive enhancement first. So, let's look at where the rubber hits the road.

(Some clever-clogs may point out that alt attributes are technically graceful degredation, which I concede. But the mindset - ensuring that as many people as possible get a decent, usable experience - is the same.)

Semantic HTML

This is so obvious that it shouldn't even need saying, but there are still many web developers who don't use the wealth of HTML elements available to us. We've all seen code like this:

<div><span>My Really Big Title</span></div>
<p>My first paragraph.</p>
<div><strong>My Subtitle</strong></div>
<p>My second paragraph.</p>

Use of paragraphs: tick. But those titles - what's wrong with <h1> - <h6>? Six levels of headings not enough for ya, eh?

And what about this monstrosity:

<div>
List item 1<br />
List item 2<br />
List item 3
</div>

There are lots of HTML elements, and using them will ensure that machines (read: Google) understands the semantic meaning of your HTML documents. Plus you get to write simpler CSS (no more .intro div:nth-child(2) strong { color: red; }).

HTML isn't a complex language, and pretty much every IDE and text editor that I know of will help you write well-formed markup. So there's no excuse. HTML is where a web page starts.

Forms

There's a huge wealth of JavaScript libraries that allow you to provide really rich form elements to users, and many of these can make your forms easier to use. But what happens when that script fails? Do you have a fallback?

Far too many forms I see contain code like this:

<div id="widget7">
  <div><span><span></div>
</div>

Erm, what is that thing? Maybe there's a clever script that turns this into a drag-and-drop file upload area, but if that script fails the user gets ... nothing. Figure out what the basic elements you have in your form are, then enhance them with richer equivalents through JavaScript.

Polyfills are a great way to do this. My favourite at the moment is rangeslider.js by André Ruffert which will make <input type="range"> work all the way back to IE8. For more polyfills check out the excellent caniuse.com, each feature has polyfills in the 'Resources' tab.

I see Mr Nitpicker at the back saying, again, that polyfills are graceful degredation not progressive enhancement. Yes they are, but there is a difference between polyfilling HTML elements that will - eventually - be supported by all browsers and using non-standard or non-functional elements that will break in ALL browsers if the script fails.

Images

Responsive images are a hot topic at the moment, and while there has been near-endless debate about exactly how to handle images in a world with gazillions of screen sizes the fog is clearing and we have a definite path ahead of us. Just to be clear: responsive design (and that includes responsive images) is progressive enhancement - everyone will get something usable, but those who support newer technologies (media queries, <picture> etc) will get something a bit better.

At this point I could just copy and paste all the recent A List Apart article on responsive images but instead I'll just tell you to go read and implement the advice in the recent A List Apart article on responsive images.

Wrapping up

Hopefully this article has been a useful primer and call-to-arms. If it's made you feel uncomfortable about how you develop your pages I'm glad: we should continually challenge ourselves to improve.

If it's true that a founding principle of the web is accessibility to all (and it is) then we have a duty to ensure our sites will work for as many people as possible.

Chris Taylor on 1st April 2015. Related talks and lectures:


If you enjoyed this you might like our talks and lectures.