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).
Most web developers build for a homogeneous user: latest device, latest OS, latest Chromium-based browser. This is hostile to:
Like all accessibility work, the result is a better experience for all users, not just the edge cases.
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:
.no-js is removed, everything works normally.no-js stays — use it to style accordingly.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>
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; }
Four levels of no-JS messaging, from worst to best:
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; }
A dedicated page at /no-js/ documenting:
This is a resource for informed decision-making — which is the user's right.