Container queries let components respond to their container's size, not the viewport.
The Problem with Media Queries#
1/* Media queries check viewport width */
2@media (min-width: 768px) {
3 .card { display: flex; }
4}
5
6/* But the same card in a sidebar needs different breakpoints */
7/* Container queries solve this */Basic Container Queries#
1/* Define a container */
2.card-container {
3 container-type: inline-size;
4 container-name: card;
5}
6
7/* Query the container */
8@container card (min-width: 400px) {
9 .card {
10 display: flex;
11 gap: 1rem;
12 }
13
14 .card-image {
15 width: 40%;
16 }
17}
18
19@container card (min-width: 600px) {
20 .card {
21 gap: 2rem;
22 }
23
24 .card-title {
25 font-size: 1.5rem;
26 }
27}Container Types#
1/* Size containment for width queries */
2.container {
3 container-type: inline-size;
4}
5
6/* Full size containment (width and height) */
7.container {
8 container-type: size;
9}
10
11/* Shorthand */
12.container {
13 container: card / inline-size;
14}Practical Card Component#
1.card-wrapper {
2 container-type: inline-size;
3}
4
5.card {
6 display: grid;
7 gap: 1rem;
8 padding: 1rem;
9}
10
11/* Stack layout for narrow containers */
12@container (max-width: 299px) {
13 .card-content {
14 text-align: center;
15 }
16}
17
18/* Side-by-side for medium containers */
19@container (min-width: 300px) {
20 .card {
21 grid-template-columns: 1fr 2fr;
22 }
23}
24
25/* Featured layout for wide containers */
26@container (min-width: 500px) {
27 .card {
28 grid-template-columns: 1fr 1fr;
29 }
30
31 .card-title {
32 font-size: 1.5rem;
33 }
34}Container Query Units#
.element {
font-size: 5cqw; /* 5% of container width */
padding: 2cqi; /* 2% of container inline size */
width: 50cqmin; /* 50% of smaller dimension */
}Style Queries#
1.card-wrapper {
2 container-type: normal;
3 --theme: light;
4}
5
6@container style(--theme: dark) {
7 .card {
8 background: #1a1a1a;
9 color: white;
10 }
11}Container queries make truly reusable components that adapt to their context.