CSS Container Queries
Build truly responsive components that adapt to their container size, not just the viewport. Covers container query syntax, use cases vs media queries, component-driven responsive design, and the patterns that make components reusable across any layout context.
Media queries respond to the browser viewport. Container queries respond to the size of the component’s parent container. This is the difference between “is the screen small?” and “is this component’s space small?” Container queries let you build components that adapt to where they are placed — in a sidebar, a full-width section, or a card grid — without knowing anything about the page layout.
Container Queries vs. Media Queries
/* Media Query: Responds to viewport size */
/* Problem: Component doesn't know if it's in a sidebar or main content */
@media (max-width: 768px) {
.card { flex-direction: column; }
}
/* Container Query: Responds to container size */
/* Component adapts to its OWN available space */
.card-container {
container-type: inline-size;
container-name: card-wrapper;
}
@container card-wrapper (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 150px 1fr;
gap: 1rem;
}
}
@container card-wrapper (max-width: 399px) {
.card {
display: flex;
flex-direction: column;
}
.card-image {
width: 100%;
aspect-ratio: 16/9;
}
}
Real-World Use Cases
/* Responsive card component that works anywhere */
.widget-area {
container-type: inline-size;
}
/* Stats widget: horizontal when wide, stacked when narrow */
@container (min-width: 500px) {
.stats-widget {
display: flex;
justify-content: space-between;
align-items: center;
}
.stat-item {
text-align: center;
flex: 1;
border-right: 1px solid var(--color-border);
}
.stat-item:last-child {
border-right: none;
}
}
@container (max-width: 499px) {
.stats-widget {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
}
.stat-item {
padding: 0.75rem;
background: var(--color-bg-secondary);
border-radius: var(--radius-md);
}
}
/* Navigation: horizontal tabs when wide, hamburger when narrow */
@container (min-width: 600px) {
.nav-tabs {
display: flex;
gap: 0;
}
.nav-hamburger { display: none; }
}
@container (max-width: 599px) {
.nav-tabs {
display: none;
}
.nav-tabs.open {
display: flex;
flex-direction: column;
position: absolute;
width: 100%;
}
.nav-hamburger { display: block; }
}
Anti-Patterns
| Anti-Pattern | Consequence | Fix |
|---|---|---|
| Container queries for everything | Unnecessary complexity for simple layouts | Use media queries for page layout, container queries for components |
| No fallback for older browsers | Component breaks in Safari < 16 | Feature query: @supports (container-type: inline-size) |
| container-type: size | Requires explicit height, causes layout issues | Use container-type: inline-size for most cases |
| Deeply nested containers | Performance impact, confusing cascade | Limit nesting to 2-3 levels |
| Not setting container-name | Ambiguous which container is queried | Always name containers explicitly |
Container queries complete the responsive design toolkit. Media queries handle page-level layout; container queries handle component-level adaptation. Together, they let you build components that are truly reusable — dropping into any layout context and adapting intelligently.