Cours HTML et CSS · Module 9: CSS moderne

Container Queries - La réactivité basée sur le conteneur

15 min de lecture
Dans cette leçon6

Ta carte d'artefact a fière allure dans la large colonne de la galerie, mais dans l'étroit panneau latéral, elle se déforme, et la media query ne remarque rien, car la fenêtre du navigateur n'a pas changé. La carte ne sait pas dans quelle chambre elle se trouve. Les Container Queries sont une fonctionnalité CSS qui permet de créer des composants responsive en fonction de la taille de leur conteneur, plutôt que de la fenêtre du navigateur. C'est une avancée majeure qui permet des mises en page véritablement modulaires.

Ce que tu vas apprendre

  • transformer un élément en conteneur et écrire une requête @container,
  • nommer des conteneurs et combiner des conditions avec des opérateurs,
  • distinguer les tâches des Container Queries de celles des media queries,
  • utiliser les unités de conteneur, comme cqw.

Les bases des Container Queries

Que sont les Container Queries ?

Les Container Queries te permettent d'appliquer des styles en fonction de la taille du conteneur parent, et non du viewport, les composants réagissent donc à leur contexte local. Compare les deux requêtes :

1/* Media Queries traditionnelles - basées sur le viewport */
2@media (max-width: 768px) {
3  .card {
4    flex-direction: column;
5  }
6}
7
8/* Container Queries - basées sur la taille du conteneur */
9@container (max-width: 400px) {
10  .card {
11    flex-direction: column;
12  }
13}

Les deux règles disposent la carte en colonne. La syntaxe des conditions reste la même, seul le point de référence change : la fenêtre ou le conteneur.

Définir un contexte de conteneur

Pour utiliser les Container Queries, nous devons d'abord définir un élément comme conteneur avec la propriété container-type :

1.container {
2  container-type: inline-size; /* Surveille la largeur */
3}
4
5.container {
6  container-type: size; /* Surveille la largeur et la hauteur */
7}
8
9.container {
10  container-type: normal; /* Valeur par défaut - aucune surveillance */
11}
12
13/* Forme abrégée avec un nom de conteneur */
14.sidebar {
15  container: sidebar / inline-size;
16}

inline-size suit la largeur et suffit presque toujours. size suit aussi la hauteur, mais l'élément cesse alors de tirer sa hauteur de son contenu. La règle la plus importante : un élément ne peut pas s'interroger lui-même, donc les règles dans @container stylent les descendants du conteneur. L'ordre de travail : container-type sur le parent, un nom facultatif dans container-name, la requête @container, les styles des enfants et un test à différentes largeurs.

Applications pratiques des Container Queries

1. Carte produit réactive

Ici, le conteneur est toute la grille de produits, et les cartes sont ses descendantes, qui changent de disposition en même temps qu'elle :

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/* Lorsque le conteneur est étroit - disposition verticale */
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/* Lorsque le conteneur est plus large - disposition horizontale */
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}

On interroge la largeur de toute la grille, et non celle d'une seule carte. Si chaque carte doit réagir séparément, fais de son enveloppe le conteneur.

2. Navigation adaptative

Tu peux nommer un conteneur, et la requête @container nav n'interroge alors que ce conteneur, même si un autre se trouve plus près :

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/* Navigation compacte pour les petits conteneurs */
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  /* Masquer le texte et n'afficher que les icônes */
37  .nav-text {
38    display: none;
39  }
40
41  .nav-icon {
42    display: block;
43    font-size: 1.5rem;
44  }
45}
46
47/* Navigation complète pour les conteneurs plus grands */
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}

Jusqu'à 600px, la navigation devient une liste verticale d'icônes, et à partir de 601px, elle affiche les liens complets avec leur texte.

3. Tableau de bord avec widgets flexibles

Dans le tableau de bord, chaque widget est lui-même un conteneur, il affichera donc plus ou moins de détails selon qu'il se trouve dans une colonne étroite ou large :

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/* Petit widget - informations de base */
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/* Widget moyen - plus de détails */
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/* Grand widget - détails complets */
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}

Les trois plages ne se chevauchent pas, c'est pourquoi un seul ensemble de styles s'applique à chaque fois.

Techniques avancées des Container Queries

1. Opérateurs logiques

Tu combines les conditions avec les mots and, or et not, comme dans les media queries. Ici, le conteneur est le parent du composant :

1.component-wrapper {
2  container-type: inline-size; /* le parent est le conteneur */
3}
4
5/* Combiner des 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) or (min-width: 800px) {
14  .component {
15    border: 2px solid red;
16  }
17}
18
19/* Négation */
20@container not (min-width: 400px) {
21  .component {
22    font-size: 0.9rem;
23  }
24}

L'enveloppe est le conteneur, car .component ne pourrait pas s'interroger lui-même. La troisième règle s'applique chaque fois que le conteneur est plus étroit que 400px.

2. Conteneurs imbriqués

Plusieurs conteneurs peuvent fonctionner en même temps sur une page, l'un dans l'autre, et les noms indiquent lequel tu interroges :

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/* Styles différents selon le contexte */
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}

Une requête avec un nom cherche l'ancêtre le plus proche portant ce nom, et une requête sans nom prend le conteneur le plus proche, quel qu'il soit.

3. Container Queries avec CSS Grid

Les Container Queries se combinent parfaitement avec Grid. La galerie a de une à quatre colonnes, selon la largeur de son enveloppe :

1.gallery-wrapper {
2  container-type: inline-size; /* l'enveloppe de la galerie est le conteneur */
3}
4
5/* Galerie réactive basée sur la taille du conteneur */
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/* Images adaptatives */
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}

Le conteneur est .gallery-wrapper, car la galerie ne peut pas interroger sa propre largeur. Dans un conteneur large, les photos deviennent des carrés avec une légende qui glisse au survol du curseur.

Container Queries vs Media Queries

Quand utiliser les Container Queries ?

Les deux techniques se complètent : les Container Queries servent aux composants, et les media queries aux changements de toute la page :

1/* Bon usage des Container Queries */
2.component {
3  container-type: inline-size;
4}
5
6/* Composants pouvant être utilisés dans différents contextes */
7@container (max-width: 300px) {
8  .card {
9    /* Styles pour un conteneur étroit */
10    flex-direction: column;
11  }
12}
13
14/* Media Queries pour les changements globaux */
15@media (max-width: 768px) {
16  body {
17    font-size: 14px;
18  }
19
20  .global-header {
21    padding: 1rem;
22  }
23}
24
25/* N'utilise pas les Container Queries pour des changements globaux */
26@container (max-width: 768px) {
27  body { /* Cela ne fonctionnera pas comme prévu */
28    font-size: 14px;
29  }
30}

La dernière règle ne fonctionnera pas, car body n'a aucun conteneur au-dessus de lui. Laisse les changements globaux aux media queries.

Exemple pratique - Carte modulaire

Le même HTML de carte de profil se trouve une fois dans la large colonne principale, et une fois dans l'étroit panneau latéral :

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">John Smith</h3>
9          <p class="role">Développeur Frontend</p>
10          <p class="description">Passionné par la création d'expériences web exceptionnelles</p>
11          <div class="actions">
12            <button class="btn primary">Suivre</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        <!-- Même carte, mais dans un conteneur plus étroit -->
24        <img src="avatar.jpg" alt="Profil" class="avatar">
25        <div class="info">
26          <h3 class="name">John Smith</h3>
27          <p class="role">Développeur Frontend</p>
28          <p class="description">Passionné par la création d'expériences web exceptionnelles</p>
29          <div class="actions">
30            <button class="btn primary">Suivre</button>
31            <button class="btn secondary">Message</button>
32          </div>
33        </div>
34      </div>
35    </div>
36  </aside>
37</div>

Les deux copies ont un code identique. Les styles ci-dessous feront en sorte que chaque carte s'adapte à son conteneur .card-container :

1/* CSS avec 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/* Conteneur étroit - disposition verticale */
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; /* Masquer dans un conteneur étroit */
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/* Conteneur moyen - disposition mixte */
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/* Conteneur large - disposition complète */
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}

Dans le panneau, la carte se dispose verticalement et masque la description, tandis que dans la colonne principale, elle affiche tout, sans une seule media query.

Bonnes pratiques des Container Queries

1. Performance et optimisation

Choisis le type de conteneur le plus restreint dont tu as besoin, regroupe les règles qui partagent les mêmes seuils et évite d'imbriquer les requêtes :

1/* N'utilise que le type de conteneur nécessaire */
2.width-only {
3  container-type: inline-size; /* Meilleur pour les performances */
4}
5
6.both-dimensions {
7  container-type: size; /* Uniquement quand tu as besoin de la hauteur */
8}
9
10/* Regroupe les points de rupture similaires */
11@container (max-width: 400px) {
12  .component-a { /* styles */ }
13  .component-b { /* styles */ }
14  .component-c { /* styles */ }
15}
16
17/* Évite une imbrication excessive */
18@container (min-width: 300px) {
19  @container (max-width: 600px) { /* Difficile à gérer */
20    .component { /* styles */ }
21  }
22}

Un @container imbriqué est valide, mais difficile à lire, alors combine plutôt les conditions avec l'opérateur and.

2. Solution de repli pour les navigateurs anciens

Les Container Queries fonctionnent dans tous les principaux navigateurs depuis 2023, et @supports permet de les ajouter comme une amélioration :

1/* Repli sans 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 comme amélioration */
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}

Chaque navigateur reçoit les styles de base, et les plus récents obtiennent en plus la disposition qui dépend du conteneur. Rien ne casse.

Unités des Container Queries

Les Container Queries introduisent des unités spéciales qui font référence à la taille du conteneur :

UnitéDescription
cqw1 % de la largeur du conteneur (container query width)
cqh1 % de la hauteur du conteneur (container query height)
cqi1 % de la taille inline du conteneur (container query inline)
cqb1 % de la taille block du conteneur (container query block)

Utilisons l'unité cqw pour que le titre de la carte grandisse avec son conteneur :

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

Ces unités fonctionnent comme vw et vh, mais par rapport au conteneur. Quand un élément n'a aucun conteneur au-dessus de lui, elles se calculent par rapport à la fenêtre.

Mon conseil : réserve les media queries à la mise en page, et construis les composants avec les Container Queries. Plus loin dans ce module, tu découvriras le sélecteur :has(), qui style un parent en fonction de ses enfants et forme avec les Container Queries le duo de la responsivité moderne. Dans le bac à sable ci-dessous, ajoute container-type: inline-size à .card-container et observe la carte.

Souviens-toi : une media query demande la taille de tout le palais, et une container query celle de la chambre où se trouve ton composant.

Code de cette leçon : index.html
1<!DOCTYPE html>
2<html lang="en">
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>Scarabée</h2>
16                    <p>Symbole de la renaissance dans l'Égypte ancienne.</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>La clé de vie - symbole de l'éternité.</p>
28                </div>
29            </div>
30        </div>
31    </div>
32</body>
33</html>

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Que sont les Container Queries en CSS ?

  2. 2. Comment définit-on un conteneur pour les Container Queries ?

Tâches pratiques dans le jeu

  • Éditeur de code

    Crée .card-container { container-type: inline-size }. À l'intérieur, ajoute une .card qui change sa flex-direction de column à row à @container (min-width: 300px). Place-la à différentes largeurs - la carte s'adaptera !

Articles utiles