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?
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:
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.
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:
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.
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.
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.
Our browser model has four components:
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.
localStorage
,
to the DOM itself.
Now we've added asynchronous communication between our client-side and server-side applications. The benefits are huge!
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 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.
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:
Medium—a platform for reading and writing articles—requires interactions with low inherent complexity.
Even the most basic Web technologies support reading and creating documents. It's a clear candidate for progressive enhancement.
Slack—a chat application—is all about real time communication in multiple channels. It needs real time updates, and to maintain state on things that aren't currently being displayed and may not be know by a server-side application.
Those are core interactions with high inherent complexity, and I'd have a hard time seeing how to use progressive enhancement to implement it.
Google Docs—a Web based document editor—is somewhere in between. It's real time collaboration features certainly have high inherent complexity, but it's still useful without those features.
A server-rendered, read-only version would make documents created with Google Docs accessible to a wider range of devices, and make them available faster on all devices.
Reading documents is a small percentage of what Google Docs does, but it's valuable, and covers a large percentage of my own use-cases.
Overall: if I were building Google Docs I'd use progressive enhancement.
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.
Almost everywhere. Probably in your application, reducing complexity to save your users from bugs, your developers from pain, and your business from higher costs.