Progressive enhancement
Why:A script doesn’t always reach the visitor: a weak network, a crash, a blocker, an old browser. Afterwards you’ll build a page whose essentials work without JavaScript while a script makes it better, and you’ll test that with the script switched off.
20 minutes
Read by speech synthesis (Qwen3-TTS); the voice is not a person’s.
Progressive enhancement is a way to build a page in layers: the essentials work in HTML without JavaScript, and a script adds conveniences on top.
The script may not arrive
Through this whole part we learned to write scripts, and it is time for an uncomfortable question: what if the script doesn’t run? Not for you: for the visitor. There are more reasons than you might think:
- the network is weak, and the page is already visible while the script is still downloading (on a train or in the countryside this is ordinary);
- there is an error in the script, for example a visitor with an old browser that lacks a feature it needs, and everything below the error never runs;
- a blocker or a company filter removed the script altogether;
- a search robot or a screen reader doesn’t run scripts at all, or doesn’t run them right away;
- the script was switched off on purpose.
If a page is built so that it is empty without the script, then in any of these cases the visitor sees nothing. If it is built so that without the script it is plainer but useful, they see the essentials. This idea is called progressive enhancement, and the UK government’s digital services (GOV.UK) made it a rule.
Layers
A page is built in layers, and each next layer only improves the previous one:
- HTML: content, links and forms. This layer works everywhere. The list of offers sits in the markup, the inquiry form submits the ordinary way, the phone is a
tel:link. - CSS: styling and layout. If the styles didn’t load, the page is ugly but readable.
- JavaScript: conveniences. The menu folds, search filters, the phone is checked as you type, the form submits without a reload.
Everything you did in the earlier lessons can be divided into “essential” and “enhancement”, and the division is very practical. The link to the inquiry form and the form itself: essential. Checking the phone while typing: an enhancement (without it the browser checks the field itself on submit, because the markup has required and type="tel").
Here are the techniques that follow from this.
- A form with
actionandmethod. Without a script the browser submits it by itself. A script that intercepts the submit (preventDefault, as in the fetch lesson) does the same thing better: without a reload and with a clear message. But it must not be able to break anything: if it didn’t load, the form stays working. - Elements needed only by the script are hidden by the markup and shown by the script. A menu button does nothing without a script, so the markup hides it (
hidden), and the script shows it and hides the list at the same time. A search field is useless without a script, so it is hidden in the markup too and appears with the script. That way there are no dud buttons. - The script checks that the elements it needs are there:
if (search) { ... }. If the markup changed, it quietly skips the enhancement instead of crashing and dragging the rest down with it. - The
<noscript>tag shows fallback content when scripts are off. Write calm text in it (“The page works without JavaScript, only search doesn’t”), not a demand like “turn it on or you’ll see nothing”.
Look at two similar visitors. In one version the page is built as an enhancement, in the other on the script alone: choose the conditions and see what is left for the visitor.
- The list of offers essential works
- The inquiry form essential works
- Phone and email essential works
- The menu button enhancement does not work
- Search in the list enhancement does not work
- Live phone check enhancement does not work
Working features: 3 of 6; of the essential ones: 3 of 3. The page is plainer, but the main things work: the visitor sees the offers, sends an inquiry and finds the contacts.
Check yourself: why is the menu button hidden in the markup rather than always visible?
Without the script it would do nothing. A dud button is worse than no button, so the script shows it itself once it is ready to run it.
How to test
Three ways, all on your own computer, with no special tool.
- Switch JavaScript off. In Chrome open the developer tools (F12), press Ctrl+Shift+P (Cmd+Shift+P on a Mac), start typing “Disable JavaScript” and choose the command. Reload the page. In Firefox the same is done with the
javascript.enabledsetting on theabout:configpage. - Slow the network down. In the Network tab, open the “No throttling” list, choose “Slow 3G” (or similar) and reload the page. You’ll see what the visitor sees in the first seconds.
- Look at the source HTML (Ctrl+U): what is in it is seen by robots and by visitors without the script. If the list of offers isn’t in it, a search engine doesn’t have it either.
Frameworks and progressive enhancement
We have already seen that a simple project in Svelte or React, without extra measures, sends an empty page until the script loads. Meta-frameworks (SvelteKit, Next.js, Astro) solve this: on the server they prepare ready HTML, so the browser gets the page at once and the script then “brings it to life”. It is the same principle you applied by hand, automated. The talk continues in the parts on site generators and Jamstack.
Practice
You’re on a 2019 site. The page you’ve been building does a lot with scripts. Walk through it with the eyes of a distrustful visitor: what happens if the scripts don’t run?
Make a table of “essential and enhancement”: five or six features of your page, and for each, what is visible without the script. Then adjust the page to fit it: add a contacts block with tel: and mailto: links, a <noscript>, hide search in the markup and show it with the script, and add the live phone check. Wrap all the enhancements in an “is the element there” check.
At the end, test for real: switch JavaScript off in the developer tools on a site you’ve downloaded, or on any page of your own, and see what is left. Our preview always runs scripts, so you have to do this check on your own machine.
What was wrong before
In the 2010s a fashion arrived for “single-page applications” that are assembled entirely by a script: the HTML came empty, and JavaScript drew everything else. Business card sites took ten seconds to open on weak phones, and for a time search engines saw a blank screen. Before that, in the era of “graceful degradation”, a page was built for the newest browsers and fallbacks were added for old ones, and almost always they were forgotten. Links with the address javascript:void(0) and a sign saying “please enable JavaScript” on an empty page were the norm.
One thing stays true: start with what must reach everyone, and add the rest on top. That is accessible, faster and more dependable all at once.
Practice
Preparing your page…
Test
Question 1 of 6
Cards
These cards go into your review once you finish the lesson.
What is progressive enhancement?
Answer
An approach: first the page works in plain HTML (content, links, forms), then CSS makes it look good, then JavaScript adds conveniences. The essentials reach everyone.
Why can’t you count on the script always being there?
Answer
It may not finish loading (a weak network), crash with an error, be blocked or be unsupported in an old browser. A page built on it is empty in those cases.
How do you handle an element that is needed only with a script?
Answer
The markup hides it (hidden) or doesn’t include it at all, and the script shows or creates it. That way there are no dud buttons without a script.
How do you test a page without JavaScript?
Answer
Switch JavaScript off in the developer tools (in Chrome: Ctrl+Shift+P, “Disable JavaScript”), slow the network down in the Network tab and look at the source HTML. The essentials should work.
How is progressive enhancement related to server rendering?
Answer
Meta-frameworks (SvelteKit, Next.js, Astro) send ready HTML and bring it to life with a script later: the same principle, automated.
Sources
- GOV.UK Service Manual: Building a resilient frontend using progressive enhancement link only, in English
- MDN: Progressive enhancement CC BY-SA, in English
- web.dev Learn HTML: Forms CC BY, in English
- Inclusive Components (Heydon Pickering) link only, in English
Next
You now know: progressive enhancement.