Kurs HTML i CSS · Moduł 9: Nowoczesny CSS
Container Queries - responsywność oparta na kontenerze
W tej lekcji6
Twoja karta artefaktu świetnie wygląda w szerokiej kolumnie galerii, ale w wąskim panelu bocznym się rozjeżdża, a media query nic nie zauważa, bo okno przeglądarki się nie zmieniło. Karta nie wie, w jakiej komnacie stoi. Container Queries to funkcjonalność CSS, która umożliwia tworzenie komponentów responsywnych w oparciu o rozmiar ich kontenera, a nie okna przeglądarki. To przełom, który pozwala na prawdziwie modularne układy.
Czego się nauczysz
- zamienisz element w kontener i napiszesz zapytanie
@container, - nazwiesz kontenery i połączysz warunki operatorami,
- odróżnisz zadania dla Container Queries i media queries,
- użyjesz jednostek kontenera, takich jak
cqw.
Podstawy Container Queries
Czym są Container Queries?
Container Queries pozwalają stosować style w zależności od rozmiaru kontenera rodzica, a nie viewport, więc komponenty reagują na swój lokalny kontekst. Porównaj oba zapytania:
1/* Tradycyjne Media Queries - bazują na viewport */
2@media (max-width: 768px) {
3 .card {
4 flex-direction: column;
5 }
6}
7
8/* Container Queries - bazują na rozmiarze kontenera */
9@container (max-width: 400px) {
10 .card {
11 flex-direction: column;
12 }
13}Obie reguły ustawiają kartę w kolumnie. Składnia warunków zostaje ta sama, zmienia się tylko punkt odniesienia: okno albo kontener.
Ustanawianie kontekstu kontenera
Aby używać Container Queries, najpierw musimy zdefiniować element jako kontener właściwością container-type:
1.container {
2 container-type: inline-size; /* Monitoruje szerokość */
3}
4
5.container {
6 container-type: size; /* Monitoruje szerokość i wysokość */
7}
8
9.container {
10 container-type: normal; /* Wartość domyślna - brak monitorowania */
11}
12
13/* Skrócona forma z nazwą kontenera */
14.sidebar {
15 container: sidebar / inline-size;
16}inline-size śledzi szerokość i wystarcza niemal zawsze. size śledzi też wysokość, ale element przestaje wtedy brać wysokość z treści. Najważniejsza zasada: element nie może odpytywać samego siebie, więc reguły w @container stylują potomków kontenera. Kolejność pracy: container-type na rodzicu, opcjonalna nazwa w container-name, zapytanie @container, style dla dzieci i test w różnych szerokościach.
Praktyczne zastosowania Container Queries
1. Responsywna karta produktu
Tutaj kontenerem jest cała siatka produktów, a karty to jej potomkowie, które zmieniają układ razem z nią:
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/* Gdy kontener jest wąski - układ pionowy */
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/* Gdy kontener jest szerszy - układ poziomy */
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}Pytamy o szerokość całej siatki, a nie pojedynczej karty. Jeśli każda karta ma reagować osobno, kontenerem zrób jej opakowanie.
2. Adaptacyjna nawigacja
Kontener możesz nazwać, a wtedy zapytanie @container nav sprawdza tylko ten kontener, nawet jeśli bliżej stoi inny:
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/* Kompaktowa nawigacja dla małych kontenerów */
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 /* Ukryj teksty i pokaż tylko ikony */
37 .nav-text {
38 display: none;
39 }
40
41 .nav-icon {
42 display: block;
43 font-size: 1.5rem;
44 }
45}
46
47/* Pełna nawigacja dla większych kontenerów */
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}Do 600px nawigacja staje się pionową listą ikon, a od 601px pokazuje pełne linki z tekstem.
3. Dashboard z elastycznymi widgetami
W panelu każdy widget sam jest kontenerem, więc w wąskiej i szerokiej kolumnie pokaże inną ilość szczegółów:
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/* Mały widget - podstawowe informacje */
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/* Średni widget - więcej szczegółów */
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/* Duży widget - pełne detale */
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}Trzy przedziały nie nachodzą na siebie, dlatego zawsze działa dokładnie jeden zestaw stylów.
Zaawansowane techniki Container Queries
1. Logiczne operatory
Warunki łączysz słowami and, or i not, tak jak w media queries. Kontenerem jest tu rodzic komponentu:
1.component-wrapper {
2 container-type: inline-size; /* kontenerem jest rodzic */
3}
4
5/* Połączenie warunków */
6@container (min-width: 300px) and (max-width: 600px) {
7 .component {
8 background: lightblue;
9 }
10}
11
12/* Alternatywa */
13@container (max-width: 300px) or (min-width: 800px) {
14 .component {
15 border: 2px solid red;
16 }
17}
18
19/* Negacja */
20@container not (min-width: 400px) {
21 .component {
22 font-size: 0.9rem;
23 }
24}Opakowanie jest kontenerem, bo .component nie mógłby odpytywać samego siebie. Trzecia reguła działa zawsze wtedy, gdy kontener jest węższy niż 400px.
2. Zagnieżdżone kontenery
Na stronie może działać wiele kontenerów naraz, jeden w drugim, a nazwy wskazują, o który z nich pytasz:
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/* Różne style w zależności od kontekstu */
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}Zapytanie z nazwą szuka najbliższego przodka o tej nazwie, a zapytanie bez nazwy bierze najbliższy kontener dowolnego rodzaju.
3. Container Queries z CSS Grid
Container Queries świetnie łączą się z Gridem. Galeria ma od jednej do czterech kolumn, zależnie od szerokości swojego opakowania:
1.gallery-wrapper {
2 container-type: inline-size; /* kontenerem jest opakowanie galerii */
3}
4
5/* Responsywna galeria bazująca na rozmiarze kontenera */
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/* Adaptacyjne zdjęcia */
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}Kontenerem jest .gallery-wrapper, bo galeria nie może pytać o własną szerokość. W szerokim kontenerze zdjęcia stają się kwadratami z podpisem wysuwanym po najechaniu kursorem.
Container Queries vs Media Queries
Kiedy używać Container Queries?
Obie techniki się uzupełniają: Container Queries służą komponentom, a media queries zmianom całej strony:
1/* Dobre zastosowanie Container Queries */
2.component {
3 container-type: inline-size;
4}
5
6/* Komponenty, które mogą być używane w różnych kontekstach */
7@container (max-width: 300px) {
8 .card {
9 /* Style dla wąskiego kontenera */
10 flex-direction: column;
11 }
12}
13
14/* Media Queries dla globalnych zmian */
15@media (max-width: 768px) {
16 body {
17 font-size: 14px;
18 }
19
20 .global-header {
21 padding: 1rem;
22 }
23}
24
25/* Nie używaj Container Queries dla globalnych zmian */
26@container (max-width: 768px) {
27 body { /* To nie zadziała jak oczekujesz */
28 font-size: 14px;
29 }
30}Ostatnia reguła nie zadziała, bo body nie ma nad sobą żadnego kontenera. Globalne zmiany zostawiaj media queries.
Praktyczny przykład - modularna karta
Ten sam HTML karty profilu stoi raz w szerokiej kolumnie głównej, a raz w wąskim panelu bocznym:
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="Profil" class="avatar">
7 <div class="info">
8 <h3 class="name">Jan Kowalski</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 <!-- Ta sama karta, ale w węższym kontenerze -->
24 <img src="avatar.jpg" alt="Profil" class="avatar">
25 <div class="info">
26 <h3 class="name">Jan Kowalski</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>Obie kopie mają identyczny kod. Style poniżej sprawią, że każda karta dopasuje się do swojego kontenera .card-container:
1/* CSS z 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/* Wąski kontener - układ pionowy */
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; /* Ukryj w wąskim kontenerze */
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/* Średni kontener - układ mieszany */
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/* Szeroki kontener - pełny układ */
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}W panelu karta staje pionowo i ukrywa opis, a w kolumnie głównej pokazuje wszystko, bez ani jednego media query.
Najlepsze praktyki Container Queries
1. Wydajność i optymalizacja
Wybieraj najwęższy potrzebny typ kontenera, grupuj reguły o tych samych progach i unikaj zagnieżdżania zapytań:
1/* Użyj tylko potrzebnego typu kontenera */
2.width-only {
3 container-type: inline-size; /* Lepsze dla wydajności */
4}
5
6.both-dimensions {
7 container-type: size; /* Tylko gdy potrzebujesz wysokości */
8}
9
10/* Grupuj podobne breakpointy */
11@container (max-width: 400px) {
12 .component-a { /* style */ }
13 .component-b { /* style */ }
14 .component-c { /* style */ }
15}
16
17/* Unikaj nadmiernego zagnieżdżania */
18@container (min-width: 300px) {
19 @container (max-width: 600px) { /* Trudne do zarządzania */
20 .component { /* style */ }
21 }
22}Zagnieżdżony @container jest poprawny, ale trudny w czytaniu, więc łącz warunki operatorem and.
2. Fallback dla starszych przeglądarek
Container Queries działają we wszystkich głównych przeglądarkach od 2023 roku, a @supports pozwala dodać je jako ulepszenie:
1/* Fallback bez 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 jako 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}Każda przeglądarka dostaje style bazowe, a nowsze dodatkowo układ zależny od kontenera. Nic się nie psuje.
Jednostki Container Query
Container Queries wprowadzają specjalne jednostki, które odnoszą się do rozmiaru kontenera:
| Jednostka | Opis |
|---|---|
cqw | 1% szerokości kontenera (container query width) |
cqh | 1% wysokości kontenera (container query height) |
cqi | 1% rozmiaru inline kontenera (container query inline) |
cqb | 1% rozmiaru block kontenera (container query block) |
Użyjmy jednostki cqw, żeby tytuł karty rósł razem z jej kontenerem:
1@container (min-width: 400px) {
2 .card-title {
3 font-size: 5cqw; /* 5% szerokości kontenera */
4 }
5}Jednostki te działają jak vw i vh, tylko względem kontenera. Gdy element nie ma nad sobą kontenera, liczą się względem okna.
Moja rada: media queries zostaw dla układu strony, a komponenty buduj z Container Queries. W dalszej części modułu poznasz selektor :has(), który stylizuje rodzica na podstawie dzieci i razem z Container Queries tworzy duet nowoczesnej responsywności. W piaskownicy poniżej dodaj container-type: inline-size do .card-container i obserwuj kartę.
Pamiętaj: media query pyta o rozmiar całego pałacu, a container query o rozmiar komnaty, w której stoi Twój komponent.
Kod do tej lekcji: index.html
1<!DOCTYPE html>
2<html lang="pl">
3<head>
4 <meta charset="UTF-8">
5 <title>Container Queries</title>
6 <link rel="stylesheet" href="style.css">
7</head>
8<body>
9 <h1>Container Queries</h1>
10 <div class="wide-wrapper">
11 <div class="card-container">
12 <div class="card">
13 <div class="card-img">IMG</div>
14 <div class="card-body">
15 <h2>Skarabeusz</h2>
16 <p>Symbol odrodzenia w starozytnym Egipcie.</p>
17 </div>
18 </div>
19 </div>
20 </div>
21 <div class="narrow-wrapper">
22 <div class="card-container">
23 <div class="card">
24 <div class="card-img">IMG</div>
25 <div class="card-body">
26 <h2>Ankh</h2>
27 <p>Klucz zycia - symbol wiecznosci.</p>
28 </div>
29 </div>
30 </div>
31 </div>
32</body>
33</html>Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Co to są Container Queries w CSS?
2. Jak zdefiniować container dla Container Queries?
Zadania praktyczne w grze
- Edytor kodu
Stwórz .card-container { container-type: inline-size }. Wewnątrz .card która przy @container (min-width: 300px) zmienia flex-direction z column na row. Umieść w różnych szerokościach - karta się dostosuje!