Container Query Fallback Strategy for Older Browsers

Ship CSS container queries safely with @supports detection, media query fallbacks, and progressive enhancement so legacy browsers still get a working — if simpler — experience.

Container vs Media

Detailed Explanation

Shipping Container Queries Without Breaking Anything

Container queries have shipped in all evergreen browsers since 2023. Even so, you may have users on locked-down enterprise browsers, embedded WebViews, or older OS versions. Here's how to deploy without regressions.

Step 1: Default to a Mobile-First Base

Write your component's CSS so the un-enhanced state works at narrow widths. Older browsers will simply receive this state at every host size.

.card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

Step 2: Wrap Enhancements in @supports

@supports (container-type: inline-size) {
  .card-host {
    container-type: inline-size;
    container-name: card;
  }

  @container card (min-width: 400px) {
    .card {
      flex-direction: row;
      align-items: flex-start;
    }
    .card img {
      width: 40%;
      max-width: 200px;
    }
  }
}

Browsers that don't understand container-type skip the entire block, keeping the simple base layout.

Step 3: Optional Media Query Fallback

If you want the horizontal layout on wide viewports even in legacy browsers (knowing the card might be in a narrow slot), add a media query outside the @supports block:

@media (min-width: 768px) {
  .card {
    flex-direction: row;
    align-items: flex-start;
  }
  .card img { width: 40%; max-width: 200px; }
}

/* And undo it for modern browsers so the container query takes over */
@supports (container-type: inline-size) {
  @media (min-width: 768px) {
    .card { flex-direction: column; }
    .card img { width: 100%; max-width: none; }
  }
}

This is more complex but ensures legacy users get a desktop layout on desktop screens, while modern users get container-aware behavior everywhere.

Step 4: JS Detection (When Necessary)

const supportsCQ = CSS.supports('container-type', 'inline-size');
document.documentElement.dataset.cq = supportsCQ ? 'yes' : 'no';

Then in CSS:

[data-cq="no"] .card { /* legacy-specific tweaks */ }

Use this only when CSS-only fallbacks aren't enough.

Polyfill Considerations

The Chrome Labs container query polyfill exists but adds JS overhead and doesn't cover every edge case. For most projects, a graceful base + @supports is enough. Reserve polyfilling for projects where legacy browser support is contractually required.

Testing Checklist

  • Component looks correct without any container query support (disable in DevTools).
  • Component progressively enhances on modern browsers.
  • No layout shift between base and enhanced states.
  • @supports block is the only place that declares container-type.

Use Case

Use this strategy when shipping container queries to production sites that must support enterprise browsers, embedded WebViews, or older OS versions. Combine @supports with a mobile-first base for safe progressive enhancement.

Try It — CSS Container Query Builder

Open full tool