Table of Contents
Progressive Enhancement
Progressive enhancement starts with a working baseline and adds enhancements on top. This is the opposite of graceful degradation (which starts with the full experience and removes things when they fail).
The Principle
- Build the baseline so it works for everyone
- Layer enhancements for users with more capable environments
- Never require an enhancement for core functionality
Why It Matters
Most web developers build for a homogeneous user: latest device, latest OS, latest Chromium-based browser. This is hostile to:
- Privacy-conscious users who block scripts by default
- Users on slow connections or older hardware
- Terminal browser users (Lynx, Bombadillo, Offpunk)
- Certain assistive technology users
- People conserving battery on mobile
Like all accessibility work, the result is a better experience for all users, not just the edge cases.
The .no-js Pattern
Start with no-js on the root element. Let JavaScript remove it if it runs:
<html lang="en" class="no-js">
// First script to run — removes the class if JS is available document.documentElement.classList.remove('no-js');
This creates two automatic states:
- JS on:
.no-jsis removed, everything works normally - JS off:
.no-jsstays — use it to style accordingly
Hiding JS-Dependent Elements
.no-js .js-required, .no-js #theme-toggle, .no-js .comments-section, .no-js .post-graph { display: none !important; }
Mark interactive elements in HTML:
<button class="theme-toggle js-required">Toggle theme</button> <div class="post-graph js-required">...</div>
Explaining, Not Just Hiding
Hiding broken elements isn't enough — explain what's happening:
.no-js .status-container::after { content: "Status updates require JavaScript to be enabled."; font-style: italic; color: var(--muted); display: block; padding: 1rem; }
The <noscript> Message
Four levels of no-JS messaging, from worst to best:
- Site breaks completely with no explanation ❌
- “You must enable JavaScript to continue” ❌
- “Some features require JavaScript” ✓
- Acknowledge the user's choice is valid, link to a dedicated page explaining what's missing and what alternatives exist ✓✓
Example of the best approach:
<noscript> <p>Welcome! I respect your decision to not use JavaScript. <a href="/no-js/">Learn more</a> about what's disabled and why.</p> </noscript>
Style the noscript block so it's visible and friendly:
noscript { display: block; background: var(--panel); border: 1px solid var(--accent-primary); padding: 1rem; margin: 1rem 0; text-align: center; border-radius: 4px; }
The /no-js/ Page
A dedicated page at /no-js/ documenting:
- What works without JavaScript (all content, navigation, RSS)
- What requires JavaScript and why
- Alternatives for each feature
- A statement that the user's choice is respected
This is a resource for informed decision-making — which is the user's right.
