Introduction
For years, Media Queries (@media) have been the foundation of responsive web design.
Media queries trigger layout changes based on the viewport width of the browser window. However, in modern component-driven development (using React, Vue, or Web Components), styling components based on the viewport has notable limitations.
For example, if you want to reuse a card component in both a wide main column and a narrow sidebar, media queries cannot detect the space available to the component, causing the layout to break.
CSS Container Queries (@container) address this limitation by allowing you to style components relative to their parent container’s width. This article covers the basics of container queries and how to apply them.
1. Viewport vs. Container Queries
Viewport-Based Media Queries
When the browser window resizes, every viewport-linked element on the page shifts layout styles at the same time.
- The Problem: The component styling depends on the overall window width, regardless of its placement on the page. This prevents you from building self-contained, modular UI elements.
Container-Based Queries
Styles are applied based on the width of the immediate parent container.
- The Benefit: A card component can automatically render a horizontal grid layout when placed in a wide main column, and swap to a stacked vertical list layout when moved into a narrow sidebar—all managed natively in CSS.
2. Basic Setup and Syntax
Implementing container queries requires two steps in your CSS:
- Register the parent element as a containment query target (
container-type). - Write styling rules for the child elements using the
@containerdirective.
HTML Structure
<!-- The Parent Container -->
<div class="card-wrapper">
<!-- The Self-Contained Card Component -->
<div class="my-card">
<img src="thumb.jpg" alt="Thumbnail" class="card-img" />
<div class="card-content">
<h3>Article Title</h3>
<p>Brief article excerpt or description text goes here...</p>
</div>
</div>
</div>
CSS Implementation
/* 1. Register the parent element as a container query context */
.card-wrapper {
/* Monitor the inline size (width) of the parent element */
container-type: inline-size;
/* Optional: Name the container context to target specific elements */
container-name: card-container;
}
/* Default mobile/stacked card styles */
.my-card {
display: flex;
flex-direction: column; /* Stack vertically */
gap: 15px;
}
/* 2. Style updates when the parent container exceeds 400px wide */
@container (min-width: 400px) {
.my-card {
flex-direction: row; /* Switch to horizontal row */
align-items: center;
}
.card-img {
width: 150px;
height: 100px;
}
}
With this configuration, the card switches to a horizontal layout as soon as .card-wrapper exceeds 400px in width, regardless of the overall browser window size.
3. Container Query Units (cqw, cqh)
Container queries also introduce new CSS units based on the dimensions of the parent container:
cqw: 1% of the container’s width.cqh: 1% of the container’s height.cqmin: The smaller value ofcqworcqh.cqmax: The larger value ofcqworcqh.
These units are useful for dynamically scaling typography based on the component’s size:
.card-content h3 {
/* Scale font size based on 5% of the parent container's width */
font-size: clamp(1rem, 5cqw, 2rem);
}
Conclusion & Browser Support
CSS Container Queries are supported across all modern browsers, including Chrome, Safari, Edge, and Firefox.
Using container queries allows you to:
- Reduce reliance on complex viewport media queries.
- Build reusable UI components that adapt to different layouts.
- Scale typography dynamically using parent container units (
cqw).
Consider adopting container queries in your CSS architecture to build more modular and maintainable responsive designs.
