Container Queries — Complete Guide
In this tutorial, you will learn about Container Queries. We cover key concepts, practical examples, and best practices to help you master this topic.
Container queries let components respond to their parent container width instead of viewport width enabling truly reusable responsive components independent of page layout.
What You'll Learn
- Container queries vs media queries
- Container types and naming
- Container query length units
- Container query syntax
- Real-world component examples
- Browser support and fallbacks
Why It Matters
- Media queries depend on viewport, not component position
- A component in a sidebar and a main area needs different styles
- Container queries make components truly reusable
- Reduces the need for multiple media query breakpoints
Real-World Use
- A card component adapts to a 2-column grid or a 4-column grid
- A sidebar widget responds to the sidebar width
- A dashboard widget fills its grid cell regardless of viewport
- A product card works in a carousel, grid, or list layout
flowchart LR
A[Component] --> B{Container Width}
B -->|Wide| C[Horizontal Layout]
B -->|Medium| D[Grid Layout]
B -->|Narrow| E[Vertical Stack]
C --> F[Same component, different containers]
D --> F
E --> F
Container Queries Basics
A container query allows a component to style itself based on its container size. Define a containment context with container-type, then query with @container.
Code Example: Simple Container Query
/* Define the container */
.card-container {
container-type: inline-size;
container-name: card;
}
/* Query the container width */
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1rem;
}
.card img {
width: 200px;
height: 150px;
}
}
@container card (min-width: 600px) {
.card {
grid-template-columns: 250px 1fr;
}
.card img {
width: 250px;
height: 200px;
}
}
/* Default narrow styles (no query needed) */
.card {
display: flex;
flex-direction: column;
}
.card img {
width: 100%;
height: auto;
}
.card-body h3 {
font-size: 1.25rem;
}
Expected output: In a narrow container (under 400px), the card stacks vertically. In a medium container (400-599px), it shows a two-column layout with a 200px image. In a wide container (600px+), the image grows to 250px.
Code Example: Product Card in Different Layouts
<div class="product-grid">
<!-- Product card in a 2-column grid -->
<div class="product-cell">
<div class="product-card">
<img src="product.jpg" alt="Product" class="product-image">
<div class="product-info">
<h3>Product Name</h3>
<p class="price">$29.99</p>
<p class="description">Short product description.</p>
<button>Add to Cart</button>
</div>
</div>
</div>
<!-- More product cards... -->
</div>
<!-- Same component in a sidebar -->
<aside class="sidebar">
<div class="product-cell">
<div class="product-card">
<img src="product.jpg" alt="Product" class="product-image">
<div class="product-info">
<h3>Product Name</h3>
<p class="price">$29.99</p>
<button>Add to Cart</button>
</div>
</div>
</div>
</aside>
<style>
/* Define containment contexts */
.product-cell {
container-type: inline-size;
container-name: product;
}
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
/* Default: vertical stack */
.product-card {
display: flex;
flex-direction: column;
border: 1px solid #eee;
border-radius: 8px;
overflow: hidden;
}
.product-image {
width: 100%;
height: auto;
}
.product-info {
padding: 1rem;
}
/* When product cell is wide enough, horizontal layout */
@container product (min-width: 350px) {
.product-card {
flex-direction: row;
}
.product-image {
width: 150px;
flex-shrink: 0;
}
}
/* When sidebar is wider than 300px */
@container sidebar (min-width: 300px) {
.product-card {
flex-direction: row;
}
.product-image {
width: 100px;
}
.description {
display: block;
}
}
@container sidebar (max-width: 299px) {
.description {
display: none;
}
}
</style>
Expected output: The same product card component adapts based on whether it is in the grid (350px cell) or the sidebar (possibly 250px). The description text is hidden in narrow sidebar containers.
Code Example: Container Query Units
.card-container {
container-type: inline-size;
container-name: dashboard;
}
.card {
/* Container query units: */
font-size: clamp(0.875rem, 3cqi, 1.25rem);
/* cqi = 1% of container inline size */
/* cqw = 1% of container width */
/* cqh = 1% of container height */
/* cqmin = smaller of cqi and cqb */
/* cqmax = larger of cqi and cqb */
padding: 2cqi;
margin-bottom: 1cqi;
}
@container dashboard (min-width: 500px) {
.card {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2cqi;
}
}
.card-title {
font-size: clamp(1rem, 4cqi, 2rem);
}
.card-value {
font-size: clamp(1.5rem, 6cqi, 3rem);
}
Expected output: Text sizes scale relative to the container. In a 400px container, 4cqi equals 16px. In an 800px container, it equals 32px (capped by clamp). This creates truly fluid components.
Common Mistakes
- Using container queries for everything — Container queries complement media queries. Use media queries for page-level layout and container queries for components.
- Forgetting container-type — Without container-type, the container query does not activate. Always set container-type: inline-size.
- Unintended container nesting — A component inside another container inherits the nearest ancestor container context. Use named containers to avoid confusion.
- No fallback for older browsers — Container queries are supported in Chrome 105+, Firefox 110+, Safari 16+. Provide a media query fallback.
- Overusing container query units — Container query units can make text too small or too large. Always use clamp() to set reasonable bounds.
- Not naming containers — Unnamed containers create implicit query scopes. Name containers explicitly for clarity.
- Performance with deeply nested containers — Each container adds some overhead. Avoid hundreds of nested queryable containers.
Practice Questions
- What is the difference between a container query and a media query? A container queries the parent element size. A media query queries the viewport size. Container queries are component-scoped.
- What CSS property establishes a containment context? container-type: inline-size (or size for both dimensions).
- What syntax is used to target a named container? @container container-name (condition) { ... }
- What does the cqi unit represent? 1 percent of the container's inline size (width in horizontal writing mode).
FAQ
Mini Project
Build a reusable media object component (image + text side by side) that uses container queries. Create three different container contexts: a wide blog post area, a narrow sidebar, and a comment thread. The media object should adapt its layout, image size, and text formatting based on the container. Add a fallback using media queries for browsers that do not support container queries. Test the component in each context and verify it adapts independently. Use container query units for padding and font sizes.
What's Next
Continue with Lesson 23: Responsive Frameworks to learn about Bootstrap, Tailwind, and other CSS frameworks for Responsive Design.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro