Web Foundations

Modern HTML Patterns

Progressive enhancement, graceful degradation, and modern features.

Advertisement

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.

Advertisement