Progressive Enhancement
Also Known As
graceful degradation
progressive enhancement
no-JS fallback
TL;DR
Building web experiences in layers — semantic HTML baseline, CSS styling, JavaScript enhancement — ensuring core functionality works without JavaScript.
Explanation
Progressive enhancement starts with a functional HTML foundation (forms that POST, links that navigate, semantic structure). CSS adds visual polish. JavaScript adds interactivity, but the page works without it. Contrast with graceful degradation (start rich, degrade). Benefits: works for users with disabled JS (corporate firewalls, accessibility tools), faster initial page load (HTML renders before JS parses), better SEO (crawlers see real content), and resilience to JS errors. PHP apps naturally support progressive enhancement — server-rendered HTML is the baseline.
Common Misconception
✗ Progressive enhancement means building for users without JavaScript — it means starting from a solid HTML foundation that works, then enhancing with JS; modern JS apps can still use this approach with server-side rendering.
Why It Matters
A form that only works via JavaScript fails for users with slow connections where JS hasn't loaded, users behind restrictive corporate proxies, and screen reader users who navigate without enabling JS.
Common Mistakes
- onClick for navigation without href — <button onclick=navigate()> breaks keyboard nav, bookmarking, and no-JS.
- Search forms that only work with JS — POST to /search should work as a native HTML form.
- Critical content rendered only by JavaScript — invisible to search engines and slow-connection users.
- AJAX-only forms with no server-rendered fallback.
Code Examples
✗ Vulnerable
<!-- JavaScript-only form — broken without JS:
<form id="search">
<input id="q" type="text">
<button onclick="doSearch()">Search</button>
</form>
<div id="results"></div>
<script>
function doSearch() {
fetch('/api/search?q=' + document.getElementById('q').value)
.then(r => r.json()).then(renderResults);
}
</script>
✓ Fixed
<!-- Works without JS (POST to server), enhanced with JS:
<form action="/search" method="GET" id="search">
<input name="q" type="search" value="<?= esc($q) ?>">
<button type="submit">Search</button>
</form>
<div id="results">
<!-- Server-rendered results here -->
<?php foreach ($results as $r): ?>
<article>...</article>
<?php endforeach; ?>
</div>
<script>
// Enhancement: AJAX search without page reload
document.getElementById('search').addEventListener('submit', async e => {
e.preventDefault(); // Override default only if JS works
// ... AJAX update
});
</script>
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
16 Mar 2026
Edited
22 Mar 2026
Views
26
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 8
Perplexity 7
Ahrefs 2
Google 2
Unknown AI 2
How they use it
crawler 20
crawler_json 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: High
⚡ Quick Fix
Build the core experience in semantic HTML first (PHP renders it), add CSS for visual enhancement, then add JavaScript for rich interactions — the content works without CSS or JS
📦 Applies To
any
web
🔗 Prerequisites
🔍 Detection Hints
Page blank or broken without JavaScript; PHP rendering JSON not HTML requiring JS to display; content inaccessible to search engines or screen readers
Auto-detectable:
✓ Yes
lighthouse
axe
w3c-validator
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: File
Tests: Update