CSS Container Queries: Real World Use Cases
Container queries are one of the most significant additions to CSS in recent years. Finally, after years of relying solely on viewport-based media queries, we can write component-level styles that respond to the size of their container rather than the entire viewport. If you've been building responsive layouts with media queries, you already understand the pain point: the same component needs different styles depending on where it's placed, and media queries can't help you there.
In this article, we'll explore practical, real-world use cases for container queries that go beyond the basic documentation. By the end, you'll have a toolkit of patterns you can apply immediately to your projects.
The Fundamental Difference: Container vs. Viewport
Before diving into use cases, let's clarify why container queries matter. Consider a card component used in both a sidebar and a main content area. With media queries, you'd need JavaScript to detect where the card is rendered, or you'd accept that the sidebar card looks cramped. With container queries, the card itself knows how to adapt based on its available space.
/* Define a containment context */
.card-wrapper {
container-type: inline-size;
container-name: card;
}
/* The card adapts to its container */
.card {
display: grid;
grid-template-columns: 1fr;
}
@container card (min-width: 400px) {
.card {
grid-template-columns: 200px 1fr;
}
}
This pattern alone solves a problem that previously required JavaScript or complex build-time processing. The container-type: inline-size property establishes a containment context on the wrapper, and then we can query that specific container's size independently of the viewport.
The container-name is optional but highly recommended. It allows us to target a specific container when we have nested containment contexts. Without it, nested containers inherit styles from their parent containers in ways that can be unexpected.
Use Case 1: Responsive Card Grids That Reflow Naturally
The classic use case is the card grid. Traditionally, you'd use CSS Grid with media queries to control how many cards appear per row. But what if your grid is used in multiple places with different widths? Perhaps one page has a three-column grid in the main content and another page uses the same cards in a narrow two-column sidebar layout.
With container queries, each card responds to its column width, making true responsive component design possible. This is the key advantage: the card component doesn't need to know anything about the grid system it lives in.
/* Container setup on the grid item wrapper */
.grid-item {
container-type: inline-size;
container-name: grid-item;
}
/* Base styles (single column) */
.product-card {
padding: 1rem;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
.product-card__image {
width: 100%;
height: auto;
border-radius: 4px;
}
/* Card takes more space when container is wide enough */
@container grid-item (min-width: 320px) {
.product-card {
display: flex;
flex-direction: row;
gap: 1rem;
}
.product-card__image {
width: 120px;
flex-shrink: 0;
}
}
This approach means the grid can be a simple responsive grid, and the cards handle their own internal layout without knowing anything about the grid context. You can reuse the same card component anywhere, and it will always look its best.
Use Case 2: Adaptive Navigation Bars
Navigation bars are notoriously difficult to make truly component-responsive. A horizontal nav works great in a header but falls apart in a sidebar or secondary header. Before container queries, you'd typically create separate navigation components for different contexts or rely on JavaScript to toggle classes based on container width.
With container queries, the navigation component itself adapts to its container:
.nav-container {
container-type: inline-size;
container-name: nav;
background: #f8f9fa;
padding: 1rem;
}
.nav-list {
display: flex;
gap: 0.5rem;
list-style: none;
padding: 0;
margin: 0;
}
.nav-link {
padding: 0.5rem 1rem;
text-decoration: none;
color: #333;
background: white;
border-radius: 4px;
transition: background 0.2s;
}
.nav-link:hover {
background: #e9ecef;
}
/* Compact vertical nav for narrow containers */
@container nav (max-width: 400px) {
.nav-list {
flex-direction: column;
}
.nav-link {
display: block;
border-bottom: 1px solid #eee;
}
}
/* Full horizontal nav for wider containers */
@container nav (min-width: 401px) {
.nav-list {
flex-direction: row;
align-items: center;
}
}
Now you can drop this navigation into a narrow sidebar or wide header, and it just works. The navigation component is truly portable and doesn't require any parent JavaScript to coordinate its layout.
Use Case 3: Embedded Content Responsiveness
Iframes and embedded content present a unique challenge. YouTube videos, for example, maintain a 16:9 aspect ratio, but their container might be 300px wide in a sidebar or 800px wide in main content. Container queries let the video wrapper itself control styling based on available space.
.video-wrapper {
container-type: inline-size;
container-name: video;
background: #000;
border-radius: 8px;
overflow: hidden;
}
.video-embed {
position: relative;
width: 100%;
padding-bottom: 56.25%; /* 16:9 aspect ratio */
}
.video-embed iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
}
/* Larger embeds get more prominence */
@container video (min-width: 600px) {
.video-wrapper {
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
}
/* Smaller embeds get minimal styling */
@container video (max-width: 599px) {
.video-wrapper {
border-radius: 4px;
}
}
Use Case 4: Form Layouts That Adapt
Forms are another area where container queries shine. A form that works as a single column in a narrow sidebar but expands to a two-column layout in a wide main area is now trivially achievable. No JavaScript required, no CSS class toggling based on container width.
.form-container {
container-type: inline-size;
container-name: form;
max-width: 100%;
}
.form-grid {
display: grid;
gap: 1rem;
}
.form-field {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.form-label {
font-weight: 600;
font-size: 0.875rem;
color: #333;
}
.form-input {
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
}
/* Stack fields vertically in narrow containers */
@container form (max-width: 500px) {
.form-grid {
grid-template-columns: 1fr;
}
}
/* Side-by-side fields in wider containers */
@container form (min-width: 501px) {
.form-grid {
grid-template-columns: 1fr 1fr;
}
.form-field--full-width {
grid-column: 1 / -1;
}
.form-field--submit {
grid-column: 1 / -1;
justify-self: end;
}
}
Use Case 5: Dashboard Widgets
Dashboards often contain widgets that need to behave differently depending on whether they're in a narrow column or a wide multi-widget row. Container queries make it natural to build widgets that adapt to their context without needing to know ahead of time where they'll be placed.
.widget-container {
container-type: inline-size;
container-name: widget;
background: white;
border-radius: 8px;
padding: 1rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.widget-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid #eee;
}
.widget-title {
font-weight: 600;
margin: 0;
}
.widget-content {
/* Widget-specific content */
}
/* Collapsed widget for narrow containers */
@container widget (max-width: 300px) {
.widget-header {
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
}
.widget-chart {
display: none;
}
.widget-mini-stats {
display: block;
}
.widget-actions {
display: none;
}
}
/* Full widget for wider containers */
@container widget (min-width: 301px) {
.widget-chart {
display: block;
}
.widget-mini-stats {
display: none;
}
.widget-actions {
display: flex;
gap: 0.5rem;
}
}
Container Query Units: cqi, cqb, and More
Beyond size queries, container queries also support container query units. These are particularly useful for fluid typography and spacing within contained components. The units include cqi (1% of container inline size), cqb (1% of container block size), cqmin, and cqmax.
.card-wrapper {
container-type: inline-size;
}
.card-title {
/* Fluid font size based on container */
font-size: clamp(1rem, 5cqi, 2rem);
}
.card-description {
/* Fluid spacing based on container */
padding: 1cqi;
}
This is incredibly powerful for creating components that scale naturally with their container, similar to how vw units work for viewport-based fluid typography, but scoped to the component itself.
Browser Support and Progressive Enhancement
As of 2026, container queries have excellent browser support across all modern browsers. According to Can I Use, container queries are supported in Chrome 105+, Firefox 110+, Safari 16+, and Edge 105+. However, it's worth implementing with a progressive enhancement approach for older browsers:
/* Fallback for browsers without container query support */
.card {
padding: 1rem;
display: block;
}
/* Progressive enhancement */
@supports (container-type: inline-size) {
.card-wrapper {
container-type: inline-size;
}
@container card (min-width: 400px) {
.card {
display: flex;
gap: 1rem;
}
}
}
This ensures your components work everywhere while taking full advantage of container queries in modern browsers.
Performance Considerations
Container queries trigger layout containment, which means the browser can optimize rendering for contained elements. Unlike some JavaScript-based solutions that listen to resize events, container queries are handled efficiently by the browser's layout engine. The containment context allows the browser to skip layout calculations for elements outside the contained subtree when the container changes.
There is a minor performance cost to containment, so avoid creating unnecessary containment contexts. Every container-type creates a new containing block that the browser must track. If you have hundreds of small containers, consider whether a single container wrapper might be more efficient.
Conclusion
Container queries represent a fundamental shift in how we think about responsive CSS. Instead of designing for fixed viewport breakpoints, we can now design truly modular components that respond to their context. The use cases above barely scratch the surface of what's possible.
The key insight is that container queries encourage better component architecture. When your components are context-aware, you write less media query code, maintain cleaner separation of concerns, and create more reusable UI elements.
Start small: pick one recurring component in your codebase that currently uses JavaScript or multiple media query overrides to adapt to different contexts. Refactor it to use container queries. Once you experience how much cleaner this approach is, you'll find yourself reaching for container queries first more often than not.
Top comments (0)