Does Progressive Enhancement have a place in today’s Web?

by George Brocklehurst (@georgebrock)

I work for thoughtbot

Presented at Windy City Rails,

This talk will try to answer the question does progressive enhancement have a place in today’s Web?


The answer the question is a resounding "yes". So maybe we should just stop here?

Drop the mic
"Drop the mic" emoji from a new emoji proposal by Microsoft.

That’s not very helpful though. Even if I’m right and it does have a place, what is that place? To understand that, we’ll try to answer three questions:

  1. What is progressive enhancement?
  2. What’s the alternative?
  3. What’s the difference?

What is Progressive Enhancement?

The Wikipedia article on Progressive Enhancement summarises it by saying:

Progressive enhancement uses web technologies in a layered fashion that allows everyone to access the basic content and functionality of a web page, using any browser or Internet connection, while also providing an enhanced version of the page to those with more advanced browser software or greater bandwidth.

You can think of it as being a bit like a sandwich. A sandwich, like a Web application, solves a problem for its user. They are hungry, and so they want to eat something. The minimum viable sandwich is just a piece of bread. It's not exciting or fun, but it gets the job done. This is like the HTML in a progressively enhanced application.

Once you've got the bread, you can add more layers to make the sandwich more interesting. These are like the CSS and JavaScript you add to your application.

Note that we shouldn't think of CSS and JavaScript as single layers. To stretch the sandwich analogy even further: some things—like your basic CSS—are more like the meat in the sandwich, others—like Web fonts, or responsive layouts—are more like condiments.

Sandwich illustration from Foundry ∞, by thoughtbot designer Will McMahan.

This gives us a lot of flexibility. If some of your lunch guests turn out to be lactose intolerant, you can still make them a pretty good sandwich by just skipping the cheese. Similarly, you can still offer your Web site's users a pretty good experience while:

What’s the alternative?

The big challenger to progressive enhancement is single-page apps. The Wikipedia article on single-page apps says:

A single-page application (SPA) is a web application or web site that fits on a single web page with the goal of providing a more fluid user experience similar to a desktop application. In an SPA, either all necessary code – HTML, JavaScript, and CSS – is retrieved with a single page load, or the appropriate resources are dynamically loaded and added to the page as necessary, usually in response to user actions.

You can think of this as less like making a sandwich, and more like making a loaf of bread. Separately the ingredients don't solve the problem; a bowl of flour isn't the minimum viable loaf. All of the ingredients have to be present to make the loaf.

On the Web, this means that the HTML, CSS, JavaScript, and often some JSON data, all have to be loaded and working before the application will do anything at all.

A loaf of bread
Bread illustration from openclipart.

This claim of this approach is that it gives users an experience that is more similar to a native application, assuming they have a fast enough Internet connection and all of the required browser features.

What’s the difference?

While there are many differences, there's one in particular I want to focus on: complexity.


Let's look at how a simple model of a browser interacts with various kinds of Web applications, so we can compare their complexity.

Browser model

Diagram of browser components.
Basic browser components (GUI illustration from Foundry ∞).

Our browser model has four components:

  1. The parser handles data coming from the network, and turns it into an internal representation the browser can use.
  2. The object model represents the DOM and CSSOM, the browser's representation of the HTML and CSS it is currently displaying.
  3. The renderer, which turns the object model into something the user can see.
  4. The GUI, where the user can see and interact with a Web page.

A server-side Web application

Diagram of browser components interacting with a server-side application.
Basic browser components interacting with a server-side application.

A Web application with server- and client-side components

Diagram of browser components interacting with a server-side application, and a JavaScript application.
Basic browser components interacting with a server-side application, and a JavaScript application.

Adding JavaScript to the picture increases the complexity. Our model browser now has a JavaScript runtime, where our JavaScript code is executed. This can receive events from the GUI, and read from or write to the object model.


A Web application with asynchronous communication between server- and client-side components

Diagram of browser components interacting with a server-side application, a JavaScript application, and asynchronous communication between them.
Basic browser components interacting with a server-side application, a JavaScript application, and asynchronous communication between them.
As Spiderman taught us: with great power comes great responsibility (illustration by camdencc on deviantart)

Now we've added asynchronous communication between our client-side and server-side applications. The benefits are huge!


Is complexity bad?

There are two kinds of complexity in software.

Inherent complexity is complexity that comes directly from the problem we're trying to solve. If we're building an app to handle filing taxes, the problem domain gives us high inherent complexity. Similarly, if we're building a Web application which needs to display updated information in real time, the inherent complexity calls for a complex architecture.

Incidental complexity is complexity that comes from a developer's decisions and could have been avoided. If you've ever had to deal with a class that was hard to understand because it had many responsibilities all jumbled together, that was an example of incidental complexity. Similarly, taking responsibility for things the browser could do for us is an example of incidental complexity.

We can't avoid inherent complexity but we can avoid incidental complexity, and we should because it makes life worse for everyone:

Progressive enhancement helps

Progressive enhancement helps us avoid incidental complexity in two ways.

It allows us to choose where to increase complexity by allowing us to choose which layers of technology we apply and which features we apply them to. Low value features can be kept very simple to reduce maintenance costs, while high value features can be enhanced with all manner of bells and whistles.

It also allows us to choose when to increase complexity by allowing us to release a simple version of a feature—or even a whole application—and iterate several times before choosing to invest in complex enhancements.

Compare this to a single page application: even the simplest features usually require changes to a server-side API and a client-side JavaScript application, along with all of the UX responsibilities of distributed systems and managing our own network requests.

How complex is your application?

Hopefully by now you're convinced that progressive enhancement can be a useful technique. Just one question remains: when should we use it?

That depends on the inherent complexity of what you're building, and specifically the interactions that you need for your core functionality.

Let's consider three examples:

Where does your application fit on that scale? I'm willing to bet very few of us are working on problems with the inherent interaction complexity of Slack.

So, where does progressive enhancement fit in today’s Web?

Almost everywhere. Probably in your application, reducing complexity to save your users from bugs, your developers from pain, and your business from higher costs.

Any questions?

Ask now, or later: @georgebrock on Twitter or email

I work for thoughtbot

These slides: