Four sentences somebody could check
On a belief with no failure condition, the four claims I use instead, and the two counters that change what the argument is even about.
A client asked what progressive enhancement meant in practice, and the 4 of us in that meeting produced about 90 seconds of gesturing.
Not adversarially. They’d read the line in our proposal, where it sits between a line about accessibility and a line about performance. They were curious. We said the site works without JavaScript, sort of, and that it degrades gracefully, and that we build from the content out.
None of which is wrong. None of it is checkable either. They could not have taken any of those sentences away and used them to figure out whether we’d done what we said. Neither could we, and that’s the part that stuck.
That was in the spring. I left in June. I’ve spent the last couple months in-house, where there’s no proposal, no signature and nobody outside the building who is ever going to ask. Which turns out to be a good way to find out whether a thing you say you believe was doing any work.
A belief you can’t fail
I think this is why the phrase has had such a strange decade. It gets held as a philosophy, and a philosophy can’t be falsified. So it survives contact with a deadline by quietly becoming a preference.
Which is a comfortable place for it to live, honestly. When the schedule gets tight, progressive enhancement isn’t a requirement being dropped, it’s a value being deprioritized, and nobody has to write that down anywhere or tell anyone it happened. I’ve done exactly that. Nobody has ever come to me at the end of a project and pointed out that the thing we promised at the start didn’t happen, because nothing we promised at the start was specific enough to not happen.
So I’ve been writing it the way I write a browser support matrix instead, as a small number of statements about what works under what conditions, each of which is either true or false about a given build. Not because a claim is morally better than a value. Because a claim can come back later and tell me I was wrong.
Four sentences
Every page’s main content is in the HTML the server returns, instead of being assembled afterward.
Every form can be completed and submitted without JavaScript, and gives the person a sensible response when it is.
Every navigation is a link with a real href that still works if you open it in a new tab, copy it or bookmark it.
Enhancements go on top of all that, and their absence leaves something usable instead of something broken.
Each of those takes about a minute to check. Turn JavaScript off in DevTools and walk the two or three journeys that make the store money. If the content is there and the form submits and the links go places, it’s true. If it isn’t, it isn’t, and now it’s a bug with a ticket on it instead of a value somebody deprioritized in a meeting nobody took notes in.
The first one is assertable in CI as well, which is what made it feel real to me instead of tidy. A check that fetches the deployed page and asserts the product name and the price appear in the raw HTML response runs to a handful of lines. It catches the regression that would otherwise arrive quietly inside somebody’s refactor a year from now.
But nobody turns it off
True, and it’s answering a question nobody asked.
The realistic failure cases have nothing to do with anybody having an opinion about JavaScript. The bundle didn’t finish downloading because a train went into a tunnel, or a corporate proxy mangled it on the way through, or a blocker took out one script and the error cascaded through everything queued behind it, or the CDN had a bad few minutes, or an older browser hit a syntax it couldn’t parse and gave up on the whole file. Most often of all, one of those third-party scripts I keep going on about threw early and nothing after it in the queue ever ran.
None of those is a person with a principle. They’re all just a normal day.
The published figures I’ve seen for how often the JavaScript doesn’t run on a big site land somewhere around 1 in 100 sessions, which sounds like nothing until you multiply it by a month of traffic. Then it’s a few thousand people looking at a spinner, or at a blank div where the thing they came for is supposed to be, and not one of them is going to contact you about it. They leave, because leaving is easier.
Go and count them
If you keep one thing from this, keep this one, and it takes an afternoon.
Put a counter in the HTML that the server increments when it renders the page. Put a second counter that only fires from JavaScript, after your bundle has parsed and run. Then leave both alone for two weeks.
<!-- rendered server-side, always present -->
<img src="/beacon?stage=html" width="1" height="1" alt="">
<!-- fires only if the bundle parsed and ran -->
<script>window.addEventListener('load', () => {
navigator.sendBeacon('/beacon?stage=js');
});</script>
The ratio between those two numbers is your JavaScript failure rate. Not a figure from an article, not my opinion against the marketing agency’s, not a position anybody has to agree with first. Yours, on your site, for the people who actually come to it.
Every time I’ve done this the number came in higher than everyone in the room guessed, and that includes me, which I mention so it’s clear I’m not grading my own homework. The conversation afterward is a different conversation entirely, because you’ve stopped arguing about whether progressive enhancement is good and started figuring out what should happen to the few thousand people a month for whom the enhancement never arrived. Those are not the same meeting.
It’s the same move as putting a number on performance instead of asking everyone to care about it a lot. An opinion gets argued with forever. A counter mostly doesn’t.
Where I’d lose the room
I’d lose credibility fast if I pretended this scales to everything, so here’s the half I’d concede before anybody makes me.
Some things genuinely can’t be done without JavaScript, and a rich text editor is one, along with a drag-and-drop page builder, a live dashboard, an interactive map. Insisting on a no-JavaScript version of those isn’t principle, it’s obstruction, and I’ve watched somebody argue for it and lose a room they deserved to lose.
What the four sentences ask for in those cases isn’t a full alternative. It’s that the failure is graceful and there’s a route out of it. A map degrades to an address, a zip code and a link that opens a mapping app. A drag-and-drop reorder degrades to a number field and a save button, which takes an hour and covers the keyboard case while you’re in there. A dashboard degrades to a page that says what’s wrong and offers a refresh, instead of an empty gray rectangle that looks exactly like a broken site, on account of being one.
And I’d concede the other half too. “The base layer is free if you start with it” is a thing developers say, me very much included. It’s mostly true and not always. On genuinely application-shaped products that base layer is real work and belongs in the estimate as real work, instead of being smuggled in as a principle by whoever is writing the estimate. I have been that person. It’s not a great way to make friends with whoever inherits the number.
Nobody to promise them to
You write this at the start instead of the end because it’s one of very few things in this job that can’t be retrofitted at a sensible price. Adding a server-rendered base layer to a finished client-side app is a rebuild with a rebuild’s number on it. Starting with one and layering on top costs some discipline and almost no money.
That was easy to say at the agency, where there was a document with a signature at the bottom of it. In-house the four sentences are exactly as true and there’s nobody on the other side to hold me to them. So they’re in the README, which nobody reads, and one of them is in CI, which everybody reads whether they want to or not. Both counters have been running since the end of July.
I still don’t know whether a claim needs somebody on the other side of it to stay a claim. A support matrix works partly because a client signs it. A budget works partly because someone has to defend the number out loud. Four sentences in a README with nobody attached to them might just be a belief again in better clothes. I won’t be able to tell for a while. Having gone looking, there’s remarkably little written about this as a practice instead of as a position, and a great many people in favor of it who’ve never published what they actually promise. If you’ve kept something like this alive in-house for longer than a year, I’d genuinely like to know how, because I’m two months in and I have no idea yet.