Container queries enable component-based responsive design. Here's how to use them effectively.
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 flex: 0 0 150px;
16 }
17}
18
19/* Shorthand */
20.card-container {
21 container: card / inline-size;
22}
23
24/* Anonymous container (no name) */
25.wrapper {
26 container-type: inline-size;
27}
28
29@container (min-width: 300px) {
30 .content {
31 font-size: 1.25rem;
32 }
33}Container Types#
1/* inline-size: Query width only (most common) */
2.sidebar {
3 container-type: inline-size;
4}
5
6/* size: Query both width and height */
7.modal {
8 container-type: size;
9}
10
11@container (min-height: 400px) {
12 .modal-content {
13 padding: 2rem;
14 }
15}
16
17/* normal: No size containment (for style queries) */
18.theme-container {
19 container-type: normal;
20 container-name: theme;
21}Responsive Card Component#
1.card-wrapper {
2 container: card / inline-size;
3}
4
5/* Default: vertical layout */
6.card {
7 display: flex;
8 flex-direction: column;
9}
10
11.card-image {
12 width: 100%;
13 aspect-ratio: 16 / 9;
14 object-fit: cover;
15}
16
17.card-content {
18 padding: 1rem;
19}
20
21.card-title {
22 font-size: 1rem;
23}
24
25/* Medium: horizontal layout */
26@container card (min-width: 400px) {
27 .card {
28 flex-direction: row;
29 }
30
31 .card-image {
32 width: 40%;
33 aspect-ratio: 1;
34 }
35
36 .card-content {
37 flex: 1;
38 display: flex;
39 flex-direction: column;
40 justify-content: center;
41 }
42
43 .card-title {
44 font-size: 1.25rem;
45 }
46}
47
48/* Large: enhanced layout */
49@container card (min-width: 600px) {
50 .card {
51 gap: 2rem;
52 }
53
54 .card-image {
55 width: 50%;
56 }
57
58 .card-title {
59 font-size: 1.5rem;
60 }
61
62 .card-meta {
63 display: flex;
64 gap: 1rem;
65 }
66}Navigation Component#
1.nav-container {
2 container: nav / inline-size;
3}
4
5.nav {
6 display: flex;
7 align-items: center;
8}
9
10.nav-links {
11 display: none;
12}
13
14.nav-menu-button {
15 display: block;
16}
17
18/* Show links when container is wide enough */
19@container nav (min-width: 600px) {
20 .nav-links {
21 display: flex;
22 gap: 1rem;
23 }
24
25 .nav-menu-button {
26 display: none;
27 }
28}
29
30/* Enhanced layout for larger containers */
31@container nav (min-width: 900px) {
32 .nav {
33 justify-content: space-between;
34 }
35
36 .nav-links {
37 gap: 2rem;
38 }
39
40 .nav-actions {
41 display: flex;
42 gap: 1rem;
43 }
44}Grid Component#
1.grid-container {
2 container: grid / inline-size;
3}
4
5.grid {
6 display: grid;
7 gap: 1rem;
8 grid-template-columns: 1fr;
9}
10
11@container grid (min-width: 400px) {
12 .grid {
13 grid-template-columns: repeat(2, 1fr);
14 }
15}
16
17@container grid (min-width: 600px) {
18 .grid {
19 grid-template-columns: repeat(3, 1fr);
20 }
21}
22
23@container grid (min-width: 900px) {
24 .grid {
25 grid-template-columns: repeat(4, 1fr);
26 gap: 1.5rem;
27 }
28}Container Query Units#
1.responsive-container {
2 container-type: inline-size;
3}
4
5.responsive-text {
6 /* Container query units */
7 font-size: clamp(1rem, 3cqi, 2rem); /* cqi = 1% of container inline size */
8 padding: 2cqi;
9
10 /* Available units:
11 cqw - container query width
12 cqh - container query height
13 cqi - container query inline size
14 cqb - container query block size
15 cqmin - smaller of cqi or cqb
16 cqmax - larger of cqi or cqb
17 */
18}
19
20/* Fluid typography based on container */
21.card-title {
22 font-size: max(1rem, 5cqi);
23}
24
25/* Responsive spacing */
26.card-content {
27 padding: clamp(1rem, 4cqi, 2rem);
28 gap: clamp(0.5rem, 2cqi, 1rem);
29}Style Queries (Experimental)#
1/* Query custom properties */
2.theme-container {
3 container-name: theme;
4 --theme: light;
5}
6
7@container theme style(--theme: dark) {
8 .content {
9 background: #1a1a1a;
10 color: white;
11 }
12}
13
14/* Query computed styles */
15@container style(display: flex) {
16 .child {
17 flex: 1;
18 }
19}Nested Containers#
1.page {
2 container: page / inline-size;
3}
4
5.sidebar {
6 container: sidebar / inline-size;
7}
8
9.main {
10 container: main / inline-size;
11}
12
13/* Query parent container */
14@container page (min-width: 1200px) {
15 .layout {
16 display: grid;
17 grid-template-columns: 300px 1fr;
18 }
19}
20
21/* Query sidebar container */
22@container sidebar (min-width: 250px) {
23 .sidebar-nav {
24 flex-direction: column;
25 }
26}
27
28/* Query main container */
29@container main (min-width: 600px) {
30 .article-grid {
31 grid-template-columns: repeat(2, 1fr);
32 }
33}Combining with Media Queries#
1.widget-container {
2 container: widget / inline-size;
3}
4
5/* Container query for component layout */
6@container widget (min-width: 400px) {
7 .widget {
8 flex-direction: row;
9 }
10}
11
12/* Media query for global adjustments */
13@media (prefers-color-scheme: dark) {
14 .widget {
15 --widget-bg: #2a2a2a;
16 --widget-text: #ffffff;
17 }
18}
19
20/* Media query for device-specific features */
21@media (hover: hover) {
22 .widget:hover {
23 transform: translateY(-2px);
24 }
25}
26
27/* Combine both */
28@media (min-width: 768px) {
29 .widget-container {
30 max-width: 50%;
31 }
32}
33
34@container widget (min-width: 300px) {
35 .widget-title {
36 font-size: 1.5rem;
37 }
38}Form Component#
1.form-container {
2 container: form / inline-size;
3}
4
5.form-group {
6 display: flex;
7 flex-direction: column;
8 gap: 0.5rem;
9}
10
11.form-row {
12 display: flex;
13 flex-direction: column;
14 gap: 1rem;
15}
16
17/* Side-by-side labels when container allows */
18@container form (min-width: 500px) {
19 .form-group {
20 flex-direction: row;
21 align-items: center;
22 }
23
24 .form-group label {
25 flex: 0 0 150px;
26 text-align: right;
27 }
28
29 .form-group input {
30 flex: 1;
31 }
32
33 .form-row {
34 flex-direction: row;
35 }
36
37 .form-row .form-group {
38 flex: 1;
39 }
40}
41
42/* Actions layout */
43@container form (min-width: 400px) {
44 .form-actions {
45 display: flex;
46 justify-content: flex-end;
47 gap: 1rem;
48 }
49}Table Component#
1.table-container {
2 container: table / inline-size;
3}
4
5/* Mobile: stack rows */
6.responsive-table {
7 display: block;
8}
9
10.responsive-table thead {
11 display: none;
12}
13
14.responsive-table tr {
15 display: block;
16 margin-bottom: 1rem;
17 border: 1px solid #ddd;
18 padding: 1rem;
19}
20
21.responsive-table td {
22 display: flex;
23 justify-content: space-between;
24}
25
26.responsive-table td::before {
27 content: attr(data-label);
28 font-weight: bold;
29}
30
31/* Desktop: normal table */
32@container table (min-width: 600px) {
33 .responsive-table {
34 display: table;
35 width: 100%;
36 }
37
38 .responsive-table thead {
39 display: table-header-group;
40 }
41
42 .responsive-table tr {
43 display: table-row;
44 margin-bottom: 0;
45 border: none;
46 padding: 0;
47 }
48
49 .responsive-table td {
50 display: table-cell;
51 }
52
53 .responsive-table td::before {
54 display: none;
55 }
56}Browser Support#
1/* Feature detection */
2@supports (container-type: inline-size) {
3 .modern-container {
4 container-type: inline-size;
5 }
6}
7
8/* Fallback for older browsers */
9.card-wrapper {
10 /* Fallback styles */
11}
12
13@supports (container-type: inline-size) {
14 .card-wrapper {
15 container: card / inline-size;
16 }
17
18 @container card (min-width: 400px) {
19 .card {
20 flex-direction: row;
21 }
22 }
23}Best Practices#
Usage:
✓ Use for component-level responsiveness
✓ Combine with media queries appropriately
✓ Name containers for clarity
✓ Use cqi units for fluid sizing
Performance:
✓ Apply containment intentionally
✓ Avoid unnecessary nesting
✓ Test with various container sizes
✓ Monitor layout shifts
Design:
✓ Design components container-first
✓ Define clear breakpoints
✓ Document container dependencies
✓ Consider content, not just size
Conclusion#
Container queries enable truly responsive components that adapt to their container rather than the viewport. Use them for reusable components like cards, navigation, and forms. Combine with media queries for device-specific features and use container units for fluid sizing.