31 March 2008

Progressive degradation

I should start this post with a disclaimer. I did not discover or invent this technique. It was suggested to me by a now ex-colleague, Marcus. He also does not like what I have named this technique. But you can make your own mind up.

We should by now all be aware of progressive enhancement, what it is and why to use it. Well, progressive degradation actually assists with progressive enhancement and in some ways turns the idea on its head to make life easier and simpler. Whenever I have employed progressive degradation, I have found things easier to develop and maintain.

Progressive enhancement generally involves writing high quality semantic markup and then layering onto that additional elements which do not in themselves add additional meaning but enhance the visual presentation of the content of a web page or make it easier and nicer to use.

Generally progressive enhancement will mean layering CSS on to the markup to make the web page look nice, and JavaScript to make the web page easier and nicer to use. Progressive degradation turns that idea on its head.

With progressive degradation, we still need high quality semantic markup. That is always the base. We are still going to layer CSS on to the markup to make the web page look nice. The big change is with the JavaScript.

Using progressive enhancement, we would write the CSS in such a way that if the user does not have a JavaScript enabled browser, the site works well and looks correct. If the user does have a JavaScript enabled browser, the JavaScript code itself would make changes to the way the CSS is applied (and perhaps to the markup as well) to give the web pages a slightly different look and additional behaviours.

Using progressive degradation, we apply the CSS to the markup in the assumption that the user has a JavaScript enabled browser. Let me just make that clear. We make the assumption that the user has JavaScript enabled within their browser.

So where is the magic? The trick is that we include an additional CSS file for those users who DO NOT have JavaScript enabled in their browser which will re-style the content to be usable without the JavaScript enhancements.

This technique is not suitable for all occasions, but when I have employed it within a website, I have found a way to use it for every enhanced element.

The major advantage of progressive degradation is that there is no page flicker as the content is altered by JavaScript code even when the JavaScript code is run on page load as the CSS code that is loaded with the page sets up the page for the JavaScript enhanced version from load.

Its an extremely simple technique to apply and the following code is all you need:


<link rel="stylesheet" href="noscript.css" type="text/css" media="screen" />


As you can see, all that is involved is the addition of a CSS file inside noscript tags. Whilst this does make the markup for your web page invalid, I believe it is a small price to pay for the power it brings. To demonstrate that power, an example could be useful.

The example I will use is that of a form which will add an item to a list. Without JavaScript, the form will always be visible. With JavaScript, there will be an add button which when clicked will show the form. How the form submission is handled here is not important but one could use an AJAX request for those user agents which support it and a postback cycle for those which do not.

The 2 versions of this page element look as follows:

With JavaScript enabled:

Without JavaScipt enabled:

The markup is as follows:

<div id="ListContainer">


<li>Item 1</li>

<li>Item 2</li>


<form action="page.html" method="post">

<label for="NewItem" id="NewItemLabel">Add item</label>

<input id="NewItem" type="text" />

<input type="submit" id="SubmitForm" value="add" />



The pertinent CSS for the purposes of this article is:
#NewItem, #SubmitForm {



This CSS will hide the input field and the submit button.

The following (somewhat rough) JavaScript will make the progressive enhancement work so that when clicking on the label for the form field, the input field and submit button will show:
<script type="text/javascript">

window.onload = function() {

document.getElementById("NewItemLabel").onclick = function() {

this.style.display = "none";

document.getElementById("NewItem").style.display = "block";

document.getElementById("SubmitForm").style.display = "block";




So, we now have a working form module as described above. When the page loads, some elements are hidden - there is no flicker whilst the JavaScript kicks in on page load and hides the relevant elements as they are already hidden! Clicking on the label will hide the label and show the relevant elements.

Now for the progressive degradation:

<style type="text/css">

#NewItem, #SubmitForm {





And that is all there is to it. Without JavaScript enabled in the web browser, the user will see the complete form. With JavaScript enabled, the user gets an enhanced experience. If you re-read the last 2 sentences, you will notice how right it sounds and yet we are mixing the concepts of progressive enhancement with those of progressive degradation.

Of course we could take this example much further, writing some JavaScript to allow the user to return the page to its load state if they changed their mind and did not actually want to add another list item. We could write code to handle the form submission etc and all this would be progressive enhancement, but progressive enhancement made even easier by starting with the concept of progressive degradation.

The key to how progressive degradation makes this easier is that we know the non-JavaScript version of the page will work perfectly and we can add as much progressive enhancement as we like and concentrate on writing fantastic JavaScript to enable exciting but as always simple and light-touch enhancements to the web pages we build.


Neil Mosafi said...

Wow another great article there boss... keep it up!


martyspain said...

Nice idea, like it! Another one for the memory banks...

Andy B said...

Spotted this on 24ways the other day, an same thing but pure JS approach...


Some extra suggestions in the comments as well.