We use cookies to enhance your experience on the site
CodeWorlds

Container Queries - Container-Based Responsiveness

Container Queries are a revolutionary CSS feature that enables creating responsive components based on the size of their container, rather than the browser window. This is a breakthrough in component design that allows for truly modular and flexible layouts.

Container Queries Basics

What Are Container Queries?

Container Queries allow you to apply styles depending on the size of the parent container, not the viewport. This means that components can react to their local context, making them more predictable and reusable.

1/* Traditional Media Queries - based on viewport */
2@media (max-width: 768px) {
3  .card {
4    flex-direction: column;
5  }
6}
7
8/* Container Queries - based on container size */
9@container (max-width: 400px) {
10  .card {
11    flex-direction: column;
12  }
13}

Establishing a Container Context

To use Container Queries, we first need to define an element as a container:

1.container {
2  container-type: inline-size; /* Monitors width */
3}
4
5.container {
6  container-type: size; /* Monitors width and height */
7}
8
9.container {
10  container-type: normal; /* Default value - no monitoring */
11}
12
13/* Shorthand with container name */
14.sidebar {
15  container: sidebar / inline-size;
16}

Practical Applications of Container Queries

1. Responsive Product Card

1.product-grid {
2  display: grid;
3  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
4  gap: 1rem;
5  container-type: inline-size;
6}
7
8.product-card {
9  background: white;
10  border-radius: 8px;
11  padding: 1rem;
12  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
13}
14
15/* When container is narrow - vertical layout */
16@container (max-width: 300px) {
17  .product-card {
18    text-align: center;
19  }
20
21  .product-card .image {
22    width: 100%;
23    margin-bottom: 1rem;
24  }
25
26  .product-card .title {
27    font-size: 1.1rem;
28    margin-bottom: 0.5rem;
29  }
30
31  .product-card .price {
32    font-size: 1.2rem;
33    color: #e74c3c;
34  }
35}
36
37/* When container is wider - horizontal layout */
38@container (min-width: 400px) {
39  .product-card {
40    display: flex;
41    align-items: center;
42    gap: 1rem;
43  }
44
45  .product-card .image {
46    width: 120px;
47    height: 120px;
48    flex-shrink: 0;
49  }
50
51  .product-card .content {
52    flex: 1;
53  }
54
55  .product-card .title {
56    font-size: 1.3rem;
57    margin-bottom: 0.5rem;
58  }
59
60  .product-card .description {
61    color: #666;
62    margin-bottom: 1rem;
63  }
64
65  .product-card .price {
66    font-size: 1.4rem;
67    font-weight: bold;
68    color: #27ae60;
69  }
70}

2. Adaptive Navigation

1.navigation {
2  container-name: nav;
3  container-type: inline-size;
4}
5
6.nav-list {
7  display: flex;
8  list-style: none;
9  margin: 0;
10  padding: 0;
11  gap: 1rem;
12}
13
14/* Compact navigation for small containers */
15@container nav (max-width: 600px) {
16  .nav-list {
17    flex-direction: column;
18    gap: 0;
19  }
20
21  .nav-item {
22    border-bottom: 1px solid #eee;
23  }
24
25  .nav-link {
26    display: block;
27    padding: 1rem;
28    text-decoration: none;
29    transition: background-color 0.2s;
30  }
31
32  .nav-link:hover {
33    background-color: #f8f9fa;
34  }
35
36  /* Hide text and show only icons */
37  .nav-text {
38    display: none;
39  }
40
41  .nav-icon {
42    display: block;
43    font-size: 1.5rem;
44  }
45}
46
47/* Full navigation for larger containers */
48@container nav (min-width: 601px) {
49  .nav-list {
50    justify-content: space-between;
51    align-items: center;
52  }
53
54  .nav-link {
55    display: flex;
56    align-items: center;
57    gap: 0.5rem;
58    padding: 0.5rem 1rem;
59    text-decoration: none;
60    border-radius: 4px;
61    transition: all 0.2s;
62  }
63
64  .nav-link:hover {
65    background-color: #007bff;
66    color: white;
67  }
68
69  .nav-text {
70    display: inline;
71  }
72
73  .nav-icon {
74    font-size: 1.2rem;
75  }
76}

3. Dashboard with Flexible Widgets

1.dashboard {
2  display: grid;
3  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
4  gap: 1rem;
5  padding: 1rem;
6}
7
8.widget {
9  background: white;
10  border-radius: 8px;
11  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
12  container-type: inline-size;
13  overflow: hidden;
14}
15
16.widget-header {
17  padding: 1rem;
18  background: #f8f9fa;
19  border-bottom: 1px solid #dee2e6;
20}
21
22.widget-content {
23  padding: 1rem;
24}
25
26/* Small widget - basic information */
27@container (max-width: 350px) {
28  .widget-header h3 {
29    font-size: 1rem;
30    margin: 0;
31  }
32
33  .widget-stats {
34    display: block;
35  }
36
37  .stat-item {
38    margin-bottom: 0.5rem;
39    text-align: center;
40  }
41
42  .stat-value {
43    font-size: 1.5rem;
44    font-weight: bold;
45    display: block;
46  }
47
48  .stat-label {
49    font-size: 0.8rem;
50    color: #666;
51  }
52
53  .chart {
54    height: 150px;
55  }
56}
57
58/* Medium widget - more details */
59@container (min-width: 351px) and (max-width: 500px) {
60  .widget-header h3 {
61    font-size: 1.2rem;
62    margin: 0;
63  }
64
65  .widget-stats {
66    display: flex;
67    justify-content: space-around;
68    margin-bottom: 1rem;
69  }
70
71  .stat-item {
72    text-align: center;
73  }
74
75  .stat-value {
76    font-size: 1.8rem;
77    font-weight: bold;
78    display: block;
79    color: #007bff;
80  }
81
82  .stat-label {
83    font-size: 0.9rem;
84    color: #666;
85  }
86
87  .chart {
88    height: 200px;
89  }
90}
91
92/* Large widget - full details */
93@container (min-width: 501px) {
94  .widget-header {
95    display: flex;
96    justify-content: space-between;
97    align-items: center;
98  }
99
100  .widget-header h3 {
101    font-size: 1.4rem;
102    margin: 0;
103  }
104
105  .widget-actions {
106    display: flex;
107    gap: 0.5rem;
108  }
109
110  .widget-stats {
111    display: grid;
112    grid-template-columns: repeat(3, 1fr);
113    gap: 1rem;
114    margin-bottom: 1.5rem;
115  }
116
117  .stat-item {
118    text-align: center;
119    padding: 1rem;
120    background: #f8f9fa;
121    border-radius: 4px;
122  }
123
124  .stat-value {
125    font-size: 2rem;
126    font-weight: bold;
127    display: block;
128    color: #28a745;
129  }
130
131  .stat-label {
132    font-size: 1rem;
133    color: #666;
134    margin-top: 0.5rem;
135  }
136
137  .chart {
138    height: 250px;
139  }
140
141  .widget-details {
142    display: block;
143    margin-top: 1rem;
144    padding-top: 1rem;
145    border-top: 1px solid #dee2e6;
146  }
147}

Advanced Container Query Techniques

1. Logical Operators

1.component {
2  container-type: inline-size;
3}
4
5/* Combining conditions */
6@container (min-width: 300px) and (max-width: 600px) {
7  .component {
8    background: lightblue;
9  }
10}
11
12/* Alternative */
13@container (max-width: 300px), (min-width: 800px) {
14  .component {
15    border: 2px solid red;
16  }
17}
18
19/* Negation */
20@container not (min-width: 400px) {
21  .component {
22    font-size: 0.9rem;
23  }
24}

2. Nested Containers

1.main-container {
2  container-name: main;
3  container-type: inline-size;
4}
5
6.sidebar {
7  container-name: sidebar;
8  container-type: inline-size;
9}
10
11.article {
12  container-name: article;
13  container-type: inline-size;
14}
15
16/* Different styles depending on context */
17@container main (min-width: 1200px) {
18  .layout {
19    display: grid;
20    grid-template-columns: 300px 1fr;
21    gap: 2rem;
22  }
23}
24
25@container sidebar (max-width: 250px) {
26  .sidebar-item {
27    padding: 0.5rem;
28  }
29
30  .sidebar-text {
31    display: none;
32  }
33}
34
35@container article (min-width: 600px) {
36  .article-content {
37    columns: 2;
38    column-gap: 2rem;
39  }
40}

3. Container Queries with CSS Grid

1.gallery {
2  container-type: inline-size;
3}
4
5/* Responsive gallery based on container size */
6@container (max-width: 400px) {
7  .gallery {
8    display: grid;
9    grid-template-columns: 1fr;
10    gap: 1rem;
11  }
12}
13
14@container (min-width: 401px) and (max-width: 800px) {
15  .gallery {
16    display: grid;
17    grid-template-columns: repeat(2, 1fr);
18    gap: 1rem;
19  }
20}
21
22@container (min-width: 801px) and (max-width: 1200px) {
23  .gallery {
24    display: grid;
25    grid-template-columns: repeat(3, 1fr);
26    gap: 1.5rem;
27  }
28}
29
30@container (min-width: 1201px) {
31  .gallery {
32    display: grid;
33    grid-template-columns: repeat(4, 1fr);
34    gap: 2rem;
35  }
36}
37
38/* Adaptive images */
39.gallery-item {
40  position: relative;
41  overflow: hidden;
42  border-radius: 8px;
43}
44
45@container (max-width: 400px) {
46  .gallery-item {
47    aspect-ratio: 16/9;
48  }
49
50  .gallery-item img {
51    width: 100%;
52    height: 100%;
53    object-fit: cover;
54  }
55
56  .gallery-caption {
57    position: absolute;
58    bottom: 0;
59    left: 0;
60    right: 0;
61    background: linear-gradient(transparent, rgba(0,0,0,0.8));
62    color: white;
63    padding: 1rem;
64    font-size: 0.9rem;
65  }
66}
67
68@container (min-width: 801px) {
69  .gallery-item {
70    aspect-ratio: 1;
71    transition: transform 0.3s ease;
72  }
73
74  .gallery-item:hover {
75    transform: scale(1.05);
76  }
77
78  .gallery-caption {
79    position: absolute;
80    bottom: 0;
81    left: 0;
82    right: 0;
83    background: rgba(0,0,0,0.9);
84    color: white;
85    padding: 1rem;
86    transform: translateY(100%);
87    transition: transform 0.3s ease;
88  }
89
90  .gallery-item:hover .gallery-caption {
91    transform: translateY(0);
92  }
93}

Container Queries vs Media Queries

When to Use Container Queries?

1/* Good use of Container Queries */
2.component {
3  container-type: inline-size;
4}
5
6/* Components that can be used in different contexts */
7@container (max-width: 300px) {
8  .card {
9    /* Styles for narrow container */
10    flex-direction: column;
11  }
12}
13
14/* Media Queries for global changes */
15@media (max-width: 768px) {
16  body {
17    font-size: 14px;
18  }
19
20  .global-header {
21    padding: 1rem;
22  }
23}
24
25/* Don't use Container Queries for global changes */
26@container (max-width: 768px) {
27  body { /* This won't work as expected */
28    font-size: 14px;
29  }
30}

Practical Example - Modular Card

1<!-- HTML -->
2<div class="page-layout">
3  <main class="main-content">
4    <div class="card-container">
5      <div class="profile-card">
6        <img src="avatar.jpg" alt="Profile" class="avatar">
7        <div class="info">
8          <h3 class="name">John Smith</h3>
9          <p class="role">Frontend Developer</p>
10          <p class="description">Passionate about creating amazing web experiences</p>
11          <div class="actions">
12            <button class="btn primary">Follow</button>
13            <button class="btn secondary">Message</button>
14          </div>
15        </div>
16      </div>
17    </div>
18  </main>
19
20  <aside class="sidebar">
21    <div class="card-container">
22      <div class="profile-card">
23        <!-- Same card, but in a narrower container -->
24        <img src="avatar.jpg" alt="Profile" class="avatar">
25        <div class="info">
26          <h3 class="name">John Smith</h3>
27          <p class="role">Frontend Developer</p>
28          <p class="description">Passionate about creating amazing web experiences</p>
29          <div class="actions">
30            <button class="btn primary">Follow</button>
31            <button class="btn secondary">Message</button>
32          </div>
33        </div>
34      </div>
35    </div>
36  </aside>
37</div>
1/* CSS with Container Queries */
2.card-container {
3  container-type: inline-size;
4}
5
6.profile-card {
7  background: white;
8  border-radius: 12px;
9  padding: 1.5rem;
10  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
11  transition: all 0.3s ease;
12}
13
14/* Narrow container - vertical layout */
15@container (max-width: 350px) {
16  .profile-card {
17    text-align: center;
18  }
19
20  .avatar {
21    width: 80px;
22    height: 80px;
23    border-radius: 50%;
24    margin: 0 auto 1rem;
25    display: block;
26  }
27
28  .name {
29    font-size: 1.2rem;
30    margin-bottom: 0.5rem;
31  }
32
33  .role {
34    color: #666;
35    font-size: 0.9rem;
36    margin-bottom: 1rem;
37  }
38
39  .description {
40    display: none; /* Hide in narrow container */
41  }
42
43  .actions {
44    display: flex;
45    flex-direction: column;
46    gap: 0.5rem;
47  }
48
49  .btn {
50    padding: 0.75rem;
51    border: none;
52    border-radius: 6px;
53    font-size: 0.9rem;
54    cursor: pointer;
55    transition: all 0.2s;
56  }
57
58  .btn.primary {
59    background: #007bff;
60    color: white;
61  }
62
63  .btn.secondary {
64    background: #f8f9fa;
65    color: #666;
66  }
67}
68
69/* Medium container - mixed layout */
70@container (min-width: 351px) and (max-width: 500px) {
71  .profile-card {
72    display: flex;
73    align-items: center;
74    gap: 1rem;
75    text-align: left;
76  }
77
78  .avatar {
79    width: 100px;
80    height: 100px;
81    border-radius: 50%;
82    flex-shrink: 0;
83  }
84
85  .info {
86    flex: 1;
87  }
88
89  .name {
90    font-size: 1.3rem;
91    margin-bottom: 0.25rem;
92  }
93
94  .role {
95    color: #666;
96    font-size: 1rem;
97    margin-bottom: 0.5rem;
98  }
99
100  .description {
101    font-size: 0.9rem;
102    color: #888;
103    margin-bottom: 1rem;
104    display: -webkit-box;
105    -webkit-line-clamp: 2;
106    -webkit-box-orient: vertical;
107    overflow: hidden;
108  }
109
110  .actions {
111    display: flex;
112    gap: 0.5rem;
113  }
114
115  .btn {
116    padding: 0.5rem 1rem;
117    border: none;
118    border-radius: 6px;
119    font-size: 0.9rem;
120    cursor: pointer;
121    transition: all 0.2s;
122  }
123
124  .btn.primary {
125    background: #007bff;
126    color: white;
127  }
128
129  .btn.secondary {
130    background: #f8f9fa;
131    color: #666;
132    border: 1px solid #dee2e6;
133  }
134}
135
136/* Wide container - full layout */
137@container (min-width: 501px) {
138  .profile-card {
139    display: flex;
140    align-items: flex-start;
141    gap: 1.5rem;
142  }
143
144  .avatar {
145    width: 120px;
146    height: 120px;
147    border-radius: 50%;
148    flex-shrink: 0;
149  }
150
151  .info {
152    flex: 1;
153  }
154
155  .name {
156    font-size: 1.5rem;
157    margin-bottom: 0.5rem;
158    font-weight: 600;
159  }
160
161  .role {
162    color: #007bff;
163    font-size: 1.1rem;
164    margin-bottom: 1rem;
165    font-weight: 500;
166  }
167
168  .description {
169    font-size: 1rem;
170    color: #555;
171    line-height: 1.6;
172    margin-bottom: 1.5rem;
173  }
174
175  .actions {
176    display: flex;
177    gap: 1rem;
178  }
179
180  .btn {
181    padding: 0.75rem 1.5rem;
182    border: none;
183    border-radius: 8px;
184    font-size: 1rem;
185    font-weight: 500;
186    cursor: pointer;
187    transition: all 0.2s;
188  }
189
190  .btn.primary {
191    background: #007bff;
192    color: white;
193  }
194
195  .btn.primary:hover {
196    background: #0056b3;
197  }
198
199  .btn.secondary {
200    background: white;
201    color: #666;
202    border: 2px solid #dee2e6;
203  }
204
205  .btn.secondary:hover {
206    border-color: #007bff;
207    color: #007bff;
208  }
209}

Container Queries Best Practices

1. Performance and Optimization

1/* Use only the needed container type */
2.width-only {
3  container-type: inline-size; /* Better for performance */
4}
5
6.both-dimensions {
7  container-type: size; /* Only when you need height */
8}
9
10/* Group similar breakpoints */
11@container (max-width: 400px) {
12  .component-a { /* styles */ }
13  .component-b { /* styles */ }
14  .component-c { /* styles */ }
15}
16
17/* Avoid excessive nesting */
18@container (min-width: 300px) {
19  @container (max-width: 600px) { /* Hard to manage */
20    .component { /* styles */ }
21  }
22}

2. Fallback for Older Browsers

1/* Fallback without Container Queries */
2.responsive-component {
3  padding: 1rem;
4  background: #f8f9fa;
5}
6
7.responsive-component .title {
8  font-size: 1.2rem;
9  margin-bottom: 1rem;
10}
11
12.responsive-component .content {
13  display: block;
14}
15
16/* Container Queries as enhancement */
17@supports (container-type: inline-size) {
18  .responsive-container {
19    container-type: inline-size;
20  }
21
22  @container (min-width: 400px) {
23    .responsive-component {
24      padding: 2rem;
25    }
26
27    .responsive-component .title {
28      font-size: 1.5rem;
29    }
30
31    .responsive-component .content {
32      display: flex;
33      gap: 1rem;
34    }
35  }
36}

Container Query Units

Container Queries introduce special units that refer to the container size:

| Unit | Description | |------|-------------| |

cqw
| 1% of container width (container query width) | |
cqh
| 1% of container height (container query height) | |
cqi
| 1% of container inline size (container query inline) | |
cqb
| 1% of container block size (container query block) |

1@container (min-width: 400px) {
2  .card-title {
3    font-size: 5cqw; /* 5% of container width */
4  }
5}

These units allow for smooth scaling of elements depending on the container size, similar to how

vw
/
vh
work relative to the viewport.

Container Queries represent the future of responsive web design, enabling the creation of truly modular components that adapt to their context regardless of viewport size. This tool fundamentally changes the way we think about responsiveness in CSS.

Go to CodeWorlds