Skip to main content

Progressive Enhancement vs Graceful Degradation

Answer​

These are two different philosophies for building web applications that work across varying browser capabilities.

Conceptual Difference​

Progressive Enhancement​

"Start simple, enhance progressively"

<!-- Layer 1: Semantic HTML (always works) -->
<form action="/search" method="GET">
<label for="search">Search:</label>
<input type="text" id="search" name="q" />
<button type="submit">Search</button>
</form>
/* Layer 2: CSS enhancement */
.search-form {
display: flex;
gap: 1rem;
}

@supports (backdrop-filter: blur(10px)) {
.search-form {
backdrop-filter: blur(10px);
}
}
// Layer 3: JavaScript enhancement
if ("IntersectionObserver" in window) {
// Use modern lazy loading
} else {
// Images load normally
}

// Layer 4: Cutting-edge features
if ("scheduler" in window) {
scheduler.postTask(() => analytics.track());
} else {
setTimeout(() => analytics.track(), 0);
}

Graceful Degradation​

"Build modern, provide fallbacks"

<!-- Modern video with fallbacks -->
<video controls>
<source src="video.webm" type="video/webm" />
<source src="video.mp4" type="video/mp4" />
<!-- Fallback for no video support -->
<p>
Your browser doesn't support video.
<a href="video.mp4">Download the video</a>.
</p>
</video>

<!-- Picture element with fallback -->
<picture>
<source srcset="image.avif" type="image/avif" />
<source srcset="image.webp" type="image/webp" />
<img src="image.jpg" alt="Fallback JPEG" />
</picture>
// Feature detection with fallback
function modernClipboard(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
return navigator.clipboard.writeText(text);
}
// Fallback
const textarea = document.createElement("textarea");
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
return Promise.resolve();
}

Comparison​

AspectProgressive EnhancementGraceful Degradation
Starting pointBasic functionalityFull functionality
ApproachBuild upFall back
Core experienceUniversalModern browsers
MaintenanceAdd new featuresFix broken fallbacks
Testing priorityOld browsers firstNew browsers first

Real-World Examples​

Progressive Enhancement​

<!-- Form works without JS -->
<form action="/subscribe" method="POST">
<input type="email" name="email" required />
<button type="submit">Subscribe</button>
</form>

<script>
// Enhance with AJAX submission
document.querySelector("form").addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(e.target);

try {
await fetch("/subscribe", {
method: "POST",
body: formData,
});
showToast("Subscribed!");
} catch {
// Fall back to normal form submission
e.target.submit();
}
});
</script>

Graceful Degradation​

// CSS Grid with flexbox fallback
const styles = `
.grid {
display: flex;
flex-wrap: wrap;
}

@supports (display: grid) {
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
}
`;

Feature Detection Best Practices​

// Modernizr-style detection
const supports = {
grid: CSS.supports("display", "grid"),
webp:
document
.createElement("canvas")
.toDataURL("image/webp")
.indexOf("data:image/webp") === 0,
intersectionObserver: "IntersectionObserver" in window,
serviceWorker: "serviceWorker" in navigator,
};

// Use feature detection, not browser detection
// ❌ Bad
if (navigator.userAgent.includes("Chrome")) {
}

// ✅ Good
if ("IntersectionObserver" in window) {
}

When to Use Each​

Progressive Enhancement:

  • Content-focused websites
  • Wide audience (varying devices/connections)
  • SEO-critical pages
  • Government/accessibility-required sites

Graceful Degradation:

  • Web applications with complex interactions
  • Internal tools with known browser requirements
  • When modern features are core to the experience

Key Points​

  • Progressive Enhancement: Core works everywhere
  • Graceful Degradation: Modern first, fallbacks added
  • Both require feature detection
  • Neither is "better" - choose based on context
  • Combine approaches as needed