CSS developers, rejoice! For over a decade, responsive design meant one thing: media queries keyed to the viewport. But components don't live in the viewport, they live in containers. Container Queries and their accompanying cq* units finally let components respond to their own context, unlocking true modularity.
Goodbye, Viewport-Coupled Components:
The problem with media queries is that a card component behaves differently depending on where it's placed. In a sidebar it's narrow; in a main column it's wide, but @media (min-width: 768px) only knows about the browser window. Container Queries solve this by letting a component respond to its nearest container.
Link to section: 1. Establishing a Container1. Establishing a Container
Use container-type to mark an element as a query container:
.sidebar {
container-type: inline-size;
/* Shorthand: container: sidebar / inline-size; */
}
.main-content {
container-type: inline-size;
}
Now any descendant can query the width of .sidebar or .main-content independently.
Link to section: 2. Querying the Container2. Querying the Container
.card {
display: grid;
gap: 1rem;
}
/* When the container is at least 400px wide, switch to a row layout */
@container (min-width: 400px) {
.card {
grid-template-columns: 120px 1fr;
align-items: center;
}
}
The same .card component adapts its layout based on the container it's placed in, with no viewport awareness required.
Link to section: 3. Container Query Units: ,[object Object]3. Container Query Units: cq*
The cq* units resolve relative to the query container, not the viewport:
.card-title {
/* 5% of the container's inline size */
font-size: 5cqmin;
/* Clamp between reasonable bounds */
font-size: clamp(1rem, 5cqmin, 2.5rem);
}
.card-image {
/* Half the container's width */
width: 50cqi;
/* Full container block size */
height: 100cqb;
}
Available units:
| Unit | Relative To |
|---|---|
cqi | Container inline size (width) |
cqb | Container block size (height) |
cqmin | Smaller of cqi or cqb |
cqmax | Larger of cqi or cqb |
cqh | Container height |
cqw | Container width |
Link to section: 4. Named Containers for Complex Layouts4. Named Containers for Complex Layouts
When nested containers get confusing, name them:
.layout {
container: layout / inline-size;
}
.sidebar {
container: sidebar / inline-size;
}
/* Query a specific named container */
@container layout (min-width: 800px) {
.sidebar { width: 300px; }
}
@container sidebar (min-width: 200px) {
.widget { display: flex; }
}
Link to section: 5. Style Container Queries5. Style Container Queries
Container Queries can also respond to custom property values, enabling style-based queries:
.card-wrapper {
container-type: style;
--theme: light;
}
.card-wrapper.dark {
--theme: dark;
}
/* Apply styles based on the container's --theme value */
@container style(--theme: dark) {
.card {
background: #1a1a1a;
color: #f0f0f0;
}
}
Link to section: 6. A Reusable Card Component6. A Reusable Card Component
.card {
container-type: inline-size;
padding: 1rem;
}
.card__media {
width: 100%;
aspect-ratio: 16 / 9;
}
/* Compact layout for narrow containers */
@container (max-width: 300px) {
.card__media { display: none; }
.card__title { font-size: 1.25rem; }
}
/* Comfortable layout for medium containers */
@container (min-width: 300px) and (max-width: 600px) {
.card__title { font-size: 1.5rem; }
}
/* Spacious layout for wide containers */
@container (min-width: 600px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
}
.card__title { font-size: 2rem; }
}
This card adapts to wherever it's dropped, whether sidebar, main column, or modal, without a single media query.
Embrace a New Era of Modular CSS:
Container Queries and cq* units mark the end of viewport-coupled responsive design. By letting components respond to their own context, these features unlock truly reusable, modular CSS that works in any layout.
MDN Web Docs: CSS Container Queries
Start exploring Container Queries and build components that adapt to their surroundings, not the viewport!