CSS Container Queries
Basic Syntax
/* 1. Define container on parent */
.card-wrapper {
container-type: inline-size;
/* or: size | normal */
}
/* 2. Named container */
.sidebar {
container-type: inline-size;
container-name: sidebar;
/* shorthand: */
container: sidebar / inline-size;
}
/* 3. Query inside container */
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 2fr;
}
}
/* 4. Query named container */
@container sidebar (min-width: 300px) {
.widget {
flex-direction: row;
}
}
Practical Example — Responsive Card
.card-grid {
container-type: inline-size;
}
.card {
/* Default: stacked layout */
display: grid;
grid-template-rows: auto 1fr auto;
gap: 12px;
padding: 16px;
}
.card__image { width: 100%; }
.card__title { font-size: 1rem; }
/* When container is wide enough: side-by-side */
@container (min-width: 480px) {
.card {
grid-template-columns: 200px 1fr;
grid-template-rows: auto auto;
align-items: start;
}
.card__image {
grid-row: 1 / -1;
height: 100%;
object-fit: cover;
}
.card__title { font-size: 1.25rem; }
}
@container (min-width: 700px) {
.card__title { font-size: 1.5rem; }
}
container-type Values
| Value | Description |
|---|---|
| inline-size | Query based on container's inline dimension (width in horizontal writing) |
| size | Query based on both inline and block dimensions |
| normal | No containment, but can be named (for style queries) |
Container vs Media Queries
| Aspect | Media Queries | Container Queries |
|---|---|---|
| Based on | Viewport width/height | Container element size |
| Reusable components | Hard — depends on layout context | Easy — component adapts to its container |
| Sidebar vs main content | Needs different class per context | One class, adapts automatically |
| Browser support | 100% | 90%+ (Chrome 105+, FF 110+, Safari 16+) |