This card switches from vertical to horizontal layout based on its container width, not the viewport.
Container QueryStacks vertically when narrow, goes horizontal at 20rem+.
Build truly responsive components with @container. Components adapt to their container's size, not the viewport. The future of responsive design.
Set container-type: inline-size on a parent, then use @container rules to style children based on the container's width. Drag the resize handle to see it adapt.
This card switches from vertical to horizontal layout based on its container width, not the viewport.
Container QueryStacks vertically when narrow, goes horizontal at 20rem+.
/* 1. Define a containment context */
.card-wrapper {
container-type: inline-size; /* track inline (width) size */
container-name: card; /* optional: name for targeting */
}
/* Shorthand */
.card-wrapper {
container: card / inline-size;
}
/* 2. Write container query rules */
@container card (min-width: 20rem) {
.card { flex-direction: row; }
.card__image { width: 40%; }
}
@container card (min-width: 32rem) {
.card__title { font-size: 1.25rem; }
}
/* container-type values:
inline-size - queries based on inline (width) dimension
size - queries based on both width and height
normal - no containment (default) */Media queries respond to the viewport size. Container queries respond to the component's container. This means the same component adapts differently depending on where it's placed.
@media = viewport-based. @container = component-based. Container queries make components truly portable.
/* Media query: responds to VIEWPORT */
@media (min-width: 768px) {
.card { flex-direction: row; }
}
/* Container query: responds to CONTAINER */
.sidebar { container-type: inline-size; }
@container (min-width: 20rem) {
.card { flex-direction: row; }
}
/* Same .card component, different contexts:
- In a narrow sidebar → stays vertical
- In a wide main area → goes horizontal
No extra classes needed! */Use container-name to target specific containers when they are nested. Without a name, @container queries the nearest ancestor container.
Purple border = outer container is wide enough. Green background = inner container is wide enough.
/* Name containers to target them specifically */
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.main {
container-type: inline-size;
container-name: main;
}
/* Query a specific container by name */
@container sidebar (min-width: 15rem) {
.widget { font-size: 0.875rem; }
}
@container main (min-width: 40rem) {
.widget { display: grid; grid-template-columns: 1fr 1fr; }
}
/* Shorthand: container: name / type */
.sidebar { container: sidebar / inline-size; }Container query units size things relative to the query container's dimensions, like vw/vh but for containers instead of the viewport.
Each bar uses cqi (container query inline) units. They scale proportionally to the container width.
/* Container query units */
.parent { container-type: inline-size; }
.child {
/* cqw = 1% of container width */
/* cqh = 1% of container height */
/* cqi = 1% of container inline size */
/* cqb = 1% of container block size */
/* cqmin = smaller of cqi/cqb */
/* cqmax = larger of cqi/cqb */
font-size: 5cqi; /* scales with container width */
padding: 2cqi 4cqi; /* proportional padding */
width: 50cqi; /* always 50% of container */
}
/* Responsive typography that scales with container */
.heading {
font-size: clamp(1rem, 5cqi, 3rem);
}A feature list component that adapts its layout based on container size. List view when narrow, card grid when wide. Drag to resize.
List → 2-column → 3-column as the container grows. Descriptions appear at 22rem+.
/* Container setup */
.features-wrapper {
container: features / inline-size;
}
/* Default: stacked list */
.features-grid {
display: grid;
grid-template-columns: 1fr;
gap: 0.75rem;
}
/* Medium: 2-column cards */
@container features (min-width: 22rem) {
.features-grid {
grid-template-columns: repeat(2, 1fr);
}
.feature-card {
flex-direction: column;
text-align: center;
}
.feature-desc { display: block; }
}
/* Large: 3-column cards */
@container features (min-width: 36rem) {
.features-grid {
grid-template-columns: repeat(3, 1fr);
}
}
/* Browser support: all modern browsers (Chrome 105+, Firefox 110+, Safari 16+) */