Frontend

CSS Container Queries: The Future of Responsive Design

Mayur Dabhi
Mayur Dabhi
May 7, 2026
13 min read

For years, responsive web design meant one thing: viewport-based media queries. We'd write @media (max-width: 768px) and call it a day. But this approach has a fundamental flaw — a component doesn't know where it lives. A sidebar card that looks fine at 320px viewport width might be crammed inside a 200px container on a wide screen. CSS Container Queries change everything by letting components respond to their parent container's size rather than the browser viewport, enabling truly reusable, context-aware components.

Why Container Queries Matter

Container Queries solve the classic design system problem: the same card component should look different when placed in a narrow sidebar versus a wide main column — without JavaScript, without wrapper hacks, and without writing duplicate media queries for every possible layout context.

@container vs @media: The Core Difference

To understand why container queries are such a big deal, you first need to feel the pain of viewport-only media queries in component-driven development.

Imagine a product card component used in three different layouts on the same page: a full-width hero section, a 3-column grid, and a narrow sidebar widget. With @media, you're always reacting to the viewport, not to where the card actually lives. You end up with brittle CSS that breaks whenever your layout changes.

@media (viewport-based) Viewport (1200px) Sidebar Card (200px wide) Broken! Main Content Card (viewport: 1200px) Looks OK Both cards react to same viewport width @container (component-based) Viewport (1200px) Sidebar Card reacts to 70px Adapts! Main Content Card reacts to 145px Adapts! container-type: inline-size container-type: inline-size

Media queries react to the viewport; container queries react to the parent container

Syntax and Setup

Container queries have a two-part syntax. First, you declare an element as a containment context using the container-type property. Then, you write rules that apply based on that container's size using the @container at-rule.

Step 1: Declare a Container

1

Set container-type on the parent

Apply container-type: inline-size to the element whose width you want child components to respond to. Use size to respond to both width and height.

CSS — Declaring a container
/* The wrapper becomes a containment context */
.card-wrapper {
    container-type: inline-size;
    /* Optional: give it a name for targeted queries */
    container-name: card;

    /* Shorthand: name / type */
    container: card / inline-size;
}

Step 2: Write @container Rules

2

Write @container rules for child elements

Inside @container, select child elements and override their styles based on the container's dimensions, just like media queries but scoped to the container.

CSS — Responding to container size
/* Default styles: stacked layout */
.card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
}

.card__image {
    width: 100%;
    aspect-ratio: 16/9;
    border-radius: 8px;
    object-fit: cover;
}

/* When the container is at least 400px wide: side-by-side layout */
@container (min-width: 400px) {
    .card {
        flex-direction: row;
        align-items: center;
    }

    .card__image {
        width: 160px;
        flex-shrink: 0;
        aspect-ratio: 1;
    }
}

/* When the container is at least 600px wide: larger text + extra info */
@container (min-width: 600px) {
    .card__title {
        font-size: 1.4rem;
    }

    .card__extra-info {
        display: block; /* Hidden by default */
    }
}

Named Containers for Precision

When you have nested containers or multiple containers on a page, named containers let you target the right ancestor. Without a name, @container matches the nearest container ancestor.

CSS — Named containers
.sidebar {
    container: sidebar / inline-size;
}

.main-content {
    container: main / inline-size;
}

/* Only triggers when the .sidebar container is narrow */
@container sidebar (max-width: 250px) {
    .widget {
        font-size: 0.85rem;
        padding: 8px;
    }
}

/* Only triggers when the .main-content container is wide */
@container main (min-width: 700px) {
    .article-card {
        display: grid;
        grid-template-columns: 200px 1fr;
    }
}
Important Gotcha

A container cannot respond to its own size — only its descendants can. If you apply container-type to .card, you cannot use @container rules to style .card itself — only its children. This is by design to prevent circular dependency loops in layout calculations.

Container Query Units

Along with the @container rule, CSS introduced a new set of length units that are relative to the queried container — similar to how vw and vh are relative to the viewport.

Unit Meaning Equivalent
cqw 1% of container's width Like vw but for container
cqh 1% of container's height Like vh but for container
cqi 1% of container's inline size Width in horizontal writing modes
cqb 1% of container's block size Height in horizontal writing modes
cqmin Smaller of cqi and cqb Like vmin
cqmax Larger of cqi and cqb Like vmax

Container query units are especially useful for fluid typography and spacing that scales with the component rather than the screen:

CSS — Container query units in practice
.widget-wrapper {
    container-type: inline-size;
}

.widget-title {
    /* Font size scales from ~14px (tiny container) to ~28px (wide container) */
    font-size: clamp(0.875rem, 4cqi, 1.75rem);
}

.widget-icon {
    /* Icon stays proportional to container */
    width: 10cqi;
    height: 10cqi;
    max-width: 48px;
    max-height: 48px;
}

.widget-padding {
    /* Padding scales with available space */
    padding: 2cqi 3cqi;
}

Real-World Use Cases

Theory is great — but container queries really shine in practical component-driven scenarios. Let's look at three patterns you can apply immediately.

1. The Adaptive Card Component

This is the canonical use case: a card that stacks vertically in a narrow grid column and switches to a horizontal layout when placed in a wider area.

<!-- In a narrow sidebar -->
<aside class="sidebar">
    <div class="card-container">
        <article class="product-card">
            <img class="product-card__img" src="shoe.jpg" alt="Running Shoe">
            <div class="product-card__body">
                <h3>Air Runner Pro</h3>
                <p class="product-card__desc">Lightweight trail shoe for serious runners.</p>
                <span class="product-card__price">$129</span>
            </div>
        </article>
    </div>
</aside>

<!-- Exact same markup in main content -->
<main class="main-grid">
    <div class="card-container">
        <article class="product-card">
            <!-- Same structure -->
        </article>
    </div>
</main>
.card-container {
    container-type: inline-size;
}

/* Base: stacked, compact */
.product-card {
    display: flex;
    flex-direction: column;
    border: 1px solid #e2e8f0;
    border-radius: 12px;
    overflow: hidden;
}

.product-card__img {
    width: 100%;
    aspect-ratio: 4/3;
    object-fit: cover;
}

.product-card__body {
    padding: 12px;
}

.product-card__desc {
    display: none; /* Hidden when too narrow */
}

/* 280px+: show description */
@container (min-width: 280px) {
    .product-card__desc {
        display: block;
        font-size: 0.85rem;
        color: #718096;
    }
}

/* 380px+: go horizontal */
@container (min-width: 380px) {
    .product-card {
        flex-direction: row;
        align-items: stretch;
    }

    .product-card__img {
        width: 140px;
        aspect-ratio: 1;
        flex-shrink: 0;
    }

    .product-card__body {
        padding: 16px;
        display: flex;
        flex-direction: column;
        justify-content: center;
    }
}

/* 560px+: full-featured hero card */
@container (min-width: 560px) {
    .product-card__img {
        width: 220px;
    }

    .product-card__price {
        font-size: 1.4rem;
        font-weight: 700;
    }
}

The same .product-card component now automatically adapts:

  • Under 280px container: Compact image-only card with title and price
  • 280–379px container: Adds description text below image
  • 380–559px container: Side-by-side image and text layout
  • 560px+ container: Spacious hero card with larger typography

No JavaScript. No layout-specific CSS classes. The component is truly self-contained.

2. Navigation That Adapts to Its Container

Navigation menus are another great candidate. A nav inside a full-width header can show all links; the same nav dropped into a sidebar should collapse into a compact list.

CSS — Adaptive navigation
.nav-wrapper {
    container-type: inline-size;
}

/* Default: vertical stack */
.nav-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    list-style: none;
    padding: 0;
}

.nav-item a {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-radius: 6px;
    text-decoration: none;
    color: inherit;
}

/* 240px+: show icon + label */
@container (min-width: 240px) {
    .nav-item .nav-label {
        display: inline;
    }
}

/* 480px+: horizontal tabs */
@container (min-width: 480px) {
    .nav-list {
        flex-direction: row;
        gap: 8px;
    }

    .nav-item a {
        padding: 10px 16px;
    }
}

3. Data Tables That Reflow

Wide tables that get squeezed into narrow panels are a UX nightmare. Container queries let you reflow table rows into cards when the container is too narrow to show all columns.

CSS — Responsive table with container queries
.table-wrapper {
    container-type: inline-size;
    overflow-x: auto;
}

table {
    width: 100%;
    border-collapse: collapse;
}

th, td {
    padding: 12px 16px;
    text-align: left;
    border-bottom: 1px solid #e2e8f0;
}

/* Below 500px: reflow to card layout */
@container (max-width: 500px) {
    table, thead, tbody, th, td, tr {
        display: block;
    }

    thead tr {
        /* Hide column headers — labels come from data-label */
        position: absolute;
        top: -9999px;
        left: -9999px;
    }

    tr {
        border: 1px solid #e2e8f0;
        border-radius: 8px;
        margin-bottom: 12px;
        padding: 8px;
    }

    td {
        border: none;
        padding: 6px 8px;
        display: flex;
        justify-content: space-between;
    }

    td::before {
        content: attr(data-label);
        font-weight: 600;
        color: #718096;
    }
}

Browser Support and Progressive Enhancement

Container queries landed in all major browsers in late 2022 and are now considered baseline-supported. You can use them in production without hesitation for most projects.

Browser @container Support Since CQ Units Support Since Global Usage
Chrome / Edge 105 (Aug 2022) 105 (Aug 2022) ~72%
Firefox 110 (Feb 2023) 110 (Feb 2023) ~4%
Safari 16 (Sep 2022) 16 (Sep 2022) ~19%
IE 11 Not supported Not supported <0.5%

Progressive Enhancement Pattern

Write your default styles first (no container queries needed), then enhance with container queries. Browsers that don't support them will simply display the default layout — perfectly acceptable as a fallback.

CSS — Progressive enhancement approach
/* Base styles work everywhere */
.card {
    display: flex;
    flex-direction: column;
    padding: 16px;
    background: white;
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

/* Optional: wrap in @supports for extra safety */
@supports (container-type: inline-size) {
    .card-wrapper {
        container-type: inline-size;
    }

    @container (min-width: 400px) {
        .card {
            flex-direction: row;
        }
    }
}

/* Can also use feature detection in JS */
if (CSS.supports('container-type', 'inline-size')) {
    document.body.classList.add('supports-cq');
}
No Polyfill Needed

Unlike many CSS features, container queries don't have a reliable polyfill for production use. The container-query-polyfill package from Google Chrome Labs works in development but adds JavaScript overhead. For production, lean on progressive enhancement — the baseline fallback is almost always acceptable.

Container Queries vs Other Responsive Techniques

@media queries + Universal support + Simple to write – Viewport-only – Context-unaware – Breaks in reuse @container queries + Context-aware + Truly reusable + No JS required ± Modern browsers ± Wrapper required JS-based (ResizeObserver) + Maximum flexibility – JS overhead – Layout thrashing risk – More complex code – Not declarative Recommended

Comparing responsive design techniques for component-level adaptation

The right choice depends on your context. Use media queries for page-level layout decisions (header height, sidebar visibility, overall column count). Use container queries for component-level adaptation (how a card, widget, or nav item renders in its allocated space). The two techniques are complementary, not competing.

Advanced Patterns and Tips

Style Queries (Experimental)

Container queries are evolving. Style queries — currently in Chrome and behind a flag in Firefox — let you query computed style values rather than dimensions. This enables theming patterns where child components adapt to a parent's custom property values:

CSS — Style queries (cutting edge)
/* Style query: respond to a CSS custom property on the container */
.card-wrapper {
    container-type: style;
    --card-variant: featured;
}

/* Children can query parent's custom property value */
@container style(--card-variant: featured) {
    .card {
        background: linear-gradient(135deg, #7c3aed, #4f46e5);
        color: white;
        transform: scale(1.02);
        box-shadow: 0 10px 40px rgba(124, 58, 237, 0.4);
    }
}

Combining with CSS Grid and Flexbox

Container queries work best when paired with intrinsic sizing. Use CSS Grid's auto-fill and minmax() to create a fluid grid, then let container queries control how each cell's content renders:

CSS — Container queries + CSS Grid
/* Grid adapts to viewport/parent */
.product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 20px;
}

/* Each cell is a container */
.product-grid > * {
    container-type: inline-size;
}

/* Card content adapts to cell width */
@container (min-width: 300px) {
    .product-card {
        /* wider card layout */
    }
}

/* For large containers (e.g. featured product slot) */
@container (min-width: 500px) {
    .product-card {
        /* hero layout */
    }
}

Container Query Quick-Reference Cheat Sheet

Feature Syntax Notes
Declare container (inline) container-type: inline-size Responds to width only
Declare container (both axes) container-type: size Responds to width & height
Name a container container-name: sidebar Enables targeted queries
Shorthand container: sidebar / inline-size name / type
Min-width query @container (min-width: 400px) Mobile-first approach
Max-width query @container (max-width: 400px) Desktop-first approach
Named query @container sidebar (min-width: 200px) Targets a specific container
CQ unit font-size: 4cqi 4% of container's inline size
Feature detection @supports (container-type: inline-size) Safe progressive enhancement

Conclusion and Key Takeaways

CSS Container Queries represent the most significant shift in responsive design thinking since media queries were introduced in CSS 2.1. They allow you to build components that are truly self-contained — components that know how to adapt to their context without any outside coordination.

Key Takeaways

  • Declare with container-type: Set container-type: inline-size on wrapper elements to create a containment context
  • Query with @container: Descendants can respond to the nearest (or named) container's dimensions
  • Use container units (cqi, cqw): Size elements proportionally to their container for fluid component scaling
  • Pair with @media, not replace it: Use media queries for page-level layout, container queries for component-level adaptation
  • Progressive enhancement: Default styles work without container query support — they're a layer of enhancement, not a dependency
  • Browser support is excellent: All major browsers have supported container queries since early 2023 — ship with confidence
"Container queries allow us to stop thinking about 'how wide is the screen?' and start thinking 'how much space does this component have?' — a fundamentally more reusable way to design."
— Una Kravets, CSS Working Group

Start small: pick one component in your current project — a card, a widget, a navigation element — and refactor it to use container queries. You'll immediately feel how much cleaner the mental model is compared to viewport media queries. Once you make the switch, you won't look back.

CSS Container Queries Responsive Design Frontend @container Web Standards
Mayur Dabhi

Mayur Dabhi

Full Stack Developer with 5+ years of experience building scalable web applications with Laravel, React, and Node.js.