Modern HTML Patterns
Progressive enhancement, graceful degradation, and modern features.
Overview
Modern HTML patterns ensure compatibility while leveraging new features.
Key Concepts
- Progressive Enhancement — Base experience for all browsers
- Graceful Degradation — Enhanced experience for modern browsers
- Feature Detection — Check browser support
- Polyfills — Add missing features
- Cutting Edge — Use latest features with fallbacks
Code Examples
<!-- Feature detection -->
<script>
function supportsWebP() {
return new Promise(resolve => {
const img = new Image();
img.onload = () => resolve(true);
img.onerror = () => resolve(false);
img.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiTvdCg==';
});
}
function supportsWebPAsync() {
return new Promise(resolve => {
const canvas = document.createElement('canvas');
resolve(canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0);
});
}
// Modern HTML features with fallbacks
document.addEventListener('DOMContentLoaded', () => {
// Dialog element support
if (!HTMLDialogElement) {
const dialog = document.querySelector('dialog');
dialog.showModal = () => { dialog.open = true; };
dialog.close = () => { dialog.open = false; };
}
// IntersectionObserver support
if (!('IntersectionObserver' in window)) {
// Fallback: load all lazy images immediately
document.querySelectorAll('img[loading="lazy"]').forEach(img => {
img.src = img.dataset.src;
});
}
// Web Animations API
if (!Element.prototype.animate) {
// Fallback: use CSS transitions
document.querySelectorAll('[data-animate]').forEach(el => {
el.classList.add('animate-fallback');
});
}
});
</script>
<!-- Loading pattern with fallback -->
<noscript>
<style>
.js-only { display: none !important; }
.noscript-message { display: block; padding: 1rem; background: #fff3cd; }
</style>
<div class="noscript-message">
JavaScript is required for the best experience.
</div>
</noscript>
<!-- Modern patterns -->
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Description" loading="lazy">
</picture>
<!-- Responsive form -->
<form>
<input type="email" required placeholder="Email">
<input type="search" placeholder="Search..." increment>
<input type="color" value="#007bff">
<input type="date">
<button type="submit">Submit</button>
</form>
<style>
/* Modern CSS with fallbacks */
.container {
display: flex;
display: -webkit-box; /* Safari */
display: -ms-flexbox; /* IE */
gap: 1rem;
-webkit-gap: 1rem; /* Safari */
}
/* Container queries */
.card {
container-type: inline-size;
}
@container (min-width: 400px) {
.card-content {
display: flex;
}
}
/* :has() selector */
.form-group:has(:invalid) {
border-color: red;
}
/* Scroll-driven animations */
@keyframes reveal {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
animation: reveal linear both;
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
</style>
Practice
Build a progressively enhanced page that works without JavaScript.