You’re on an old version of this site. Please visit danmall.me for the latest.

Progressive Enhancement. Still Alive & Kickin’.

A few days ago, I launched Sigh, JavaScript, a Tumblr that showcases sites that don’t work well with JavaScript disabled.

The day erupted with equal parts delight and criticism.

On Trolling

I’ll be the first to admit that I’m trolling, at least a bit. But I’m not trying to.

I didn’t mean to offend anyone. I know that I unfortunately and unitentionally have, and I apologize for that and have apologized to the people I know for certain I’ve offended. If anyone’s personally offended or hurt by anything there, email me and I’ll try my best to make it right. That might mean revising or editing a post. It might mean that I’ll work with you to help get your site working well for as many people as possible. Let’s talk about it.

Accountability

Once upon a time, Oakley launched a website to promote some new goggles. That website weighed in at a whopping 85.4MB. Phil Hawksworth wrote about it. Oakley worked on it and responded to Phil that they got the page weight down to 13.6MB. That’s a savings of 71.8MB or 84%. Andy Clarke worked it out; at $9/MB, the original site would cost $768 to view on an iPhone. The newly optimized site—though still large—would cost $122, quite literally saving you $646. I’m sure there’s more to the story that we don’t know, but the simplified version is that Phil played a part in saving someone $646.

Google tells me that “accountable” means “(of a person, organization, or institution) required or expected to justify actions or decisions.” Some people justify a site that doesn’t work with JavaScript disabled by saying, “the site is for people who have JavaScript enabled.” Sometimes, that’s a good reason and it’s true. Sometimes though, it’s the most convenient way to dodge a real problem. And sometimes, we don’t realize that “only for people who have JavaScript enabled” also means “not for anyone with a Blackberry” or “not for anyone who works at [old-school organization]” or “not for people in a developing country” or “not for people on the Edge network.”

Lots of people don’t know how to build sites that work for as many people as possible. That’s more than ok, but don’t pretend that it was your plan all along.

Sigh, JavaScript isn’t mean to be a hall of shame. It’s a litmus test. If I visit your site, turn off JavaScript, and see a dead end, I’ll take a screenshot and post it. No malice intended.

This isn’t about shame. It’s about accountability.

Better ways to make the point

All that said, I realize that there are better ways to make the point. More than a few have mentioned—both publicly and privately—that, rather than posting sites that don’t work well, I should be posting sites that do. A “sites done right” list is a wonderful suggestion, and one that I’ll be doing immediately. However, that’s not in place of a “not working well” list; I think it’s still valuable to see both ends of the spectrum.

To start that, I’ve added a post to the site about a great example of progressive enhancement done well. This will be the first of many, and they’ll be tagged as #yayjavascript from now on, so keep an eye out for them.

Even better ways

Better still, my friend Stacey Mulcahy requested a post for how to properly approach progressive enhancement, which I thought was a splendid idea.

Before I begin, I’ll say that there’s been a lot of good posts already written about the topic. Part of my motivation for creating the site was that this isn’t a new problem. Some of the best articles on the topic were written long ago. Here are a few of my favorites:

Still with me? Let’s journey on.

There are usually 1 of 2 problems that I often see with sites not properly utilizing good progressive enhancement techniques (which most of the sites on Sigh, JavaScript also suffer from):

  1. All of the content—read: markup or HTML—is generated by JavaScript.
  2. Or, the markup is good but styles are written in such a way that JavaScript is required to view the site.

This tutorial will show you how to overcome both.

A case study

A common argument for requiring JavaScript is that it’s ok for “web apps.” I still don’t know what a “web app” is; I tend to fall in the Mat Marquis/Jeremy Keith camp here.

So, let’s build an “app-y” example. Joe McCann makes a great suggestion: a real-time, trading web application. For the hungry, you can see the final example here: pest.danielmall.com. You can also get all of the code on Github, so clone/fork away. (Disclaimer: I know nothing about stocks, so don’t fault me for my stock visualization logic here.)

Step 1: write some HTML. This is already where a lot of people get it wrong; this is where problem #1 happens. Stop writing JavaScript controllers, don’t worry about routing yet, put your database schema on hold. Create structural markup for the data. In this case, I’ve used a table with 2 columns: time and share price.

HTML for Progressively Enhanced Stock Table

<h1 class="page-title">Progressively Enhanced Stock Table</h1>

<section class="last-updated">
    <h1>Last updated <span class="current-time">8:21:29 am</span>. <strong class="static-page-message"><a href="../">Refresh</a> for updates.</strong></h1>
</section><!-- .last-updated -->

<div class="stock-table-wrapper">

    <table class="stock-table">
        <thead>
            <th class="table-headers" scope="col">Time</th>
            <th class="table-headers" scope="col">Share Price</th>
        </thead>
        <tbody>
            <tr>
            <th class="time-label" scope="row">8:20:10 <abbr title="Ante Meridien">am</abbr></th>
            <td class="share-price"><span class="share-price-tooltip">$<b class="share-price-num">149</b></span></td>
        </tr>
        <tr>
            <th class="time-label" scope="row">8:20:20 <abbr title="Ante Meridien">am</abbr></th>
            <td class="share-price"><span class="share-price-tooltip">$<b class="share-price-num">146</b></span></td>
        </tr>
        <tr>
            <th class="time-label" scope="row">8:20:30 <abbr title="Ante Meridien">am</abbr></th>
            <td class="share-price"><span class="share-price-tooltip">$<b class="share-price-num">138</b></span></td>
        </tr>
        <tr>
            <th class="time-label" scope="row">8:20:40 <abbr title="Ante Meridien">am</abbr></th>
            <td class="share-price"><span class="share-price-tooltip">$<b class="share-price-num">197</b></span></td>
        </tr>
        <tr>
            <th class="time-label" scope="row">8:20:50 <abbr title="Ante Meridien">am</abbr></th>
            <td class="share-price"><span class="share-price-tooltip">$<b class="share-price-num">15</b></span></td>
        </tr>
        
        </tbody>
    </table><!-- .stock-table -->

</div><!-- .stock-table-wrapper -->
                        

The server does all the work here. (There’s a little PHP action that randomly generates the numbers, but that doesn’t really matter for this demo.) This is our barebones, baseline version. For mobile devices, slow connections, sluggish networks, we’ve got a lean mean page that doesn’t leave you lost.

Next, write some styles to get this looking good. Don’t change any markup. We’re progressively enhancing!

HTML & CSS for Progressively Enhanced Stock Table

The final bit is to add JavaScript to add real-time functionality. This is where problem #2 often comes in. I need styles that only apply when the JavaScript functionality is available. The way I do this is to add a new CSS file using JavaScript. I’ve written about this before, but think it’s worth mentioning again.

In the <head>, write this just under your main stylesheet:

<script>document.write('<link rel="stylesheet" href="/-/c/enhanced.css" />');</script>

Now you have an entire stylesheet that only loads when JavaScript does. It also does so before the page renders, so none of that FOUC crap. For me, that’s worth an extra HTTP request. (It may not for you, so there are other ways to solve this.)

In that stylesheet, you can now create styles appropriate to the real-time functionality, like converting that table into a graph and plotting the numerical data.

You can also create some JavaScript logic that alters or augments the markup already on the page. This is the other culprit of problem #1. JavaScript is an awful excellent weak powerful language. You can create full-scale software with it or you can use it for DOM manipulation. It’s both a sledgehammer and a scalpel. In my experience, the best examples of progressive enhancement go the scalpel route.

My JavaScript file for this example does a handful of things to enhance this page, like manipulating the markup for the table-to-graph conversion, adding points real-time, updating the time on the page to show that it’s real-time, and removing the prompt to refresh since it’s not necessary anymore. (The logic for the real-time data is just randomly generated, but the point of the demo is to show that any type of JavaScript algorithm you create can be used to enhance the existing markup, rather than having to create it in the first place.)

HTML, CSS, & JavaScript for Progressively Enhanced Stock Table

And there you have it: a progressively-enhanced web app/site/thang.

I promise to be more proactive about keeping progressive enhancment in mind and positive as I try and help people who are still on their way.

Do you?

blog comments powered by Disqus

Article Info