Cours HTML et CSS · Module 5: Responsive design

Projet principal - Galerie portfolio responsive de photographe

13 min de lecture
Dans cette leçon7

Un ami photographe a besoin d'un site qui présente ses photos aussi bien sur le téléphone d'un client que sur l'écran de son bureau. Dans ce projet, on va créer une galerie portfolio professionnelle et entièrement responsive pour un photographe. On va utiliser toutes les techniques de ce module : media queries, unités responsives (vw, vh), viewport, optimisation des images et approche mobile-first. La galerie comprendra une navigation, une section hero, une grille de photos avec effets au survol, un filtrage par catégorie et une lightbox pour visualiser les photos.

Description du projet

Notre galerie portfolio aura les fonctionnalités suivantes :

  • Navigation responsive - menu hamburger sur les appareils mobiles
  • Section hero - plein écran à l'aide des unités de viewport
  • Galerie de photos - grille responsive avec effets au survol
  • Filtrage par catégorie - boutons de filtre au design interactif
  • Lightbox - visualisation des photos agrandies
  • Optimisation des images - différentes tailles pour différents appareils

Étape 1 : structure HTML avec approche mobile-first

On commence par une structure HTML écrite en pensant aux téléphones. Remarque la balise viewport dans le head et les éléments picture dans la galerie :

1<!DOCTYPE html>
2<html lang="fr">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>John Smith - Portfolio de photographe</title>
7    <link rel="stylesheet" href="styles.css">
8</head>
9<body>
10    <!-- Navigation -->
11    <nav class="navbar">
12        <div class="nav-container">
13            <div class="nav-logo">JS Photography</div>
14            <button class="nav-toggle" aria-label="Menu">
15                <span></span>
16                <span></span>
17                <span></span>
18            </button>
19            <ul class="nav-menu">
20                <li><a href="#home">Accueil</a></li>
21                <li><a href="#portfolio">Portfolio</a></li>
22                <li><a href="#about">À propos</a></li>
23                <li><a href="#contact">Contact</a></li>
24            </ul>
25        </div>
26    </nav>
27
28    <!-- Section Hero -->
29    <section id="home" class="hero">
30        <div class="hero-content">
31            <h1 class="hero-title">John Smith</h1>
32            <p class="hero-subtitle">La photographie est ma passion</p>
33            <a href="#portfolio" class="hero-button">Voir le portfolio</a>
34        </div>
35        <div class="hero-overlay"></div>
36    </section>
37
38    <!-- Section Portfolio -->
39    <section id="portfolio" class="portfolio">
40        <div class="container">
41            <h2 class="section-title">Mon portfolio</h2>
42
43            <!-- Filtres de catégorie -->
44            <div class="filter-buttons">
45                <button class="filter-btn active" data-filter="all">Tout</button>
46                <button class="filter-btn" data-filter="nature">Nature</button>
47                <button class="filter-btn" data-filter="portrait">Portraits</button>
48                <button class="filter-btn" data-filter="architecture">Architecture</button>
49            </div>
50
51            <!-- Galerie -->
52            <div class="gallery">
53                <div class="gallery-item" data-category="nature">
54                    <picture>
55                        <source media="(max-width: 768px)" srcset="img/nature1-mobile.jpg">
56                        <source media="(max-width: 1200px)" srcset="img/nature1-tablet.jpg">
57                        <img src="img/nature1-desktop.jpg" alt="Paysage de montagne">
58                    </picture>
59                    <div class="gallery-overlay">
60                        <h3>Paysage de montagne</h3>
61                        <p>Nature</p>
62                    </div>
63                </div>
64
65                <div class="gallery-item" data-category="portrait">
66                    <picture>
67                        <source media="(max-width: 768px)" srcset="img/portrait1-mobile.jpg">
68                        <source media="(max-width: 1200px)" srcset="img/portrait1-tablet.jpg">
69                        <img src="img/portrait1-desktop.jpg" alt="Portrait de femme">
70                    </picture>
71                    <div class="gallery-overlay">
72                        <h3>Portrait</h3>
73                        <p>Portraits</p>
74                    </div>
75                </div>
76
77                <!-- D'autres éléments de galerie... -->
78            </div>
79        </div>
80    </section>
81
82    <!-- Lightbox -->
83    <div class="lightbox" id="lightbox">
84        <span class="lightbox-close">&times;</span>
85        <img class="lightbox-content" id="lightbox-img">
86        <div class="lightbox-caption"></div>
87    </div>
88</body>
89</html>

Le bouton nav-toggle est le hamburger, et son aria-label indique aux lecteurs d'écran à quoi il sert. Les attributs data-category préparent le filtrage. Le hamburger, les filtres et la lightbox ne prendront vie qu'avec un script que tu écriras une fois que tu connaîtras JavaScript, tandis que le CSS leur prépare déjà des états avec la classe active.

Étape 2 : CSS mobile-first avec unités responsives

On commence la mise en forme par les téléphones et on découpe la feuille de style en quatre étapes. La première comprend le reset, les variables CSS écrites une seule fois dans :root et insérées avec var(), ainsi que la navigation avec son menu caché sous le hamburger :

1/* Reset et styles de base */
2* {
3    margin: 0;
4    padding: 0;
5    box-sizing: border-box;
6}
7
8:root {
9    --primary-color: #333;
10    --secondary-color: #f4f4f4;
11    --accent-color: #ff6b6b;
12    --text-light: #fff;
13    --overlay-dark: rgba(0, 0, 0, 0.7);
14}
15
16body {
17    font-family: 'Arial', sans-serif;
18    line-height: 1.6;
19    color: var(--primary-color);
20}
21
22/* Navigation - Mobile First */
23.navbar {
24    background-color: var(--primary-color);
25    padding: 1rem;
26    position: fixed;
27    width: 100%;
28    top: 0;
29    z-index: 1000;
30}
31
32.nav-container {
33    display: flex;
34    justify-content: space-between;
35    align-items: center;
36}
37
38.nav-logo {
39    color: var(--text-light);
40    font-size: 1.5rem;
41    font-weight: bold;
42}
43
44/* Menu hamburger pour mobile */
45.nav-toggle {
46    background: none;
47    border: none;
48    cursor: pointer;
49    display: flex;
50    flex-direction: column;
51    gap: 4px;
52}
53
54.nav-toggle span {
55    width: 25px;
56    height: 3px;
57    background-color: var(--text-light);
58    transition: all 0.3s ease;
59}
60
61.nav-menu {
62    position: absolute;
63    top: 100%;
64    left: 0;
65    width: 100%;
66    background-color: var(--primary-color);
67    list-style: none;
68    display: none;
69    flex-direction: column;
70}
71
72.nav-menu.active {
73    display: flex;
74}
75
76.nav-menu li {
77    padding: 1rem;
78    text-align: center;
79}
80
81.nav-menu a {
82    color: var(--text-light);
83    text-decoration: none;
84    transition: color 0.3s ease;
85}

box-sizing: border-box empêche le padding d'élargir les éléments. La barre avec position: fixed reste en haut pendant le défilement, et le menu avec display: none attend qu'un script lui ajoute la classe active. La deuxième étape concerne la section hero, le portfolio et les filtres :

1/* Section hero avec unités de viewport */
2.hero {
3    height: 100vh;
4    width: 100vw;
5    position: relative;
6    display: flex;
7    align-items: center;
8    justify-content: center;
9    background-image: url('img/hero-mobile.jpg');
10    background-size: cover;
11    background-position: center;
12}
13
14.hero-overlay {
15    position: absolute;
16    top: 0;
17    left: 0;
18    width: 100%;
19    height: 100%;
20    background-color: var(--overlay-dark);
21}
22
23.hero-content {
24    position: relative;
25    z-index: 1;
26    text-align: center;
27    color: var(--text-light);
28    padding: 0 1rem;
29}
30
31.hero-title {
32    font-size: clamp(2rem, 8vw, 4rem);
33    margin-bottom: 1rem;
34}
35
36.hero-subtitle {
37    font-size: clamp(1rem, 4vw, 1.5rem);
38    margin-bottom: 2rem;
39}
40
41.hero-button {
42    display: inline-block;
43    padding: 0.8rem 2rem;
44    background-color: var(--accent-color);
45    color: var(--text-light);
46    text-decoration: none;
47    border-radius: 5px;
48    transition: all 0.3s ease;
49}
50
51/* Section portfolio */
52.portfolio {
53    padding: 4rem 1rem;
54    background-color: var(--secondary-color);
55}
56
57.container {
58    max-width: 1200px;
59    margin: 0 auto;
60}
61
62.section-title {
63    text-align: center;
64    font-size: clamp(1.5rem, 5vw, 2.5rem);
65    margin-bottom: 2rem;
66}
67
68/* Filtres */
69.filter-buttons {
70    display: flex;
71    flex-wrap: wrap;
72    justify-content: center;
73    gap: 0.5rem;
74    margin-bottom: 2rem;
75}
76
77.filter-btn {
78    padding: 0.5rem 1rem;
79    border: 2px solid var(--primary-color);
80    background-color: transparent;
81    cursor: pointer;
82    transition: all 0.3s ease;
83    border-radius: 25px;
84}
85
86.filter-btn.active,
87.filter-btn:hover {
88    background-color: var(--primary-color);
89    color: var(--text-light);
90}

height: 100vh correspond à toute la hauteur de la fenêtre. clamp(2rem, 8vw, 4rem) prend un minimum, une valeur préférée et un maximum, donc le titre grandit avec l'écran, sans jamais descendre sous 2rem ni dépasser 4rem. Le conteneur avec max-width: 1200px garde le contenu au centre. La troisième étape, c'est la galerie et la lightbox :

1/* Galerie - Grille Mobile First */
2.gallery {
3    display: grid;
4    grid-template-columns: 1fr;
5    gap: 1rem;
6}
7
8.gallery-item {
9    position: relative;
10    overflow: hidden;
11    cursor: pointer;
12    aspect-ratio: 1;
13}
14
15.gallery-item img {
16    width: 100%;
17    height: 100%;
18    object-fit: cover;
19    transition: transform 0.3s ease;
20}
21
22.gallery-overlay {
23    position: absolute;
24    bottom: 0;
25    left: 0;
26    right: 0;
27    background: linear-gradient(to top, var(--overlay-dark), transparent);
28    color: var(--text-light);
29    padding: 1rem;
30    transform: translateY(100%);
31    transition: transform 0.3s ease;
32}
33
34.gallery-item:hover .gallery-overlay {
35    transform: translateY(0);
36}
37
38.gallery-item:hover img {
39    transform: scale(1.1);
40}
41
42/* Lightbox */
43.lightbox {
44    display: none;
45    position: fixed;
46    z-index: 2000;
47    left: 0;
48    top: 0;
49    width: 100vw;
50    height: 100vh;
51    background-color: var(--overlay-dark);
52    align-items: center;
53    justify-content: center;
54}
55
56.lightbox.active {
57    display: flex;
58}
59
60.lightbox-content {
61    max-width: 90vw;
62    max-height: 90vh;
63    object-fit: contain;
64}
65
66.lightbox-close {
67    position: absolute;
68    top: 1rem;
69    right: 1rem;
70    color: var(--text-light);
71    font-size: 2rem;
72    cursor: pointer;
73}

Sur un téléphone, la galerie a une seule colonne 1fr. aspect-ratio: 1 transforme chaque vignette en carré, et object-fit: cover recadre la photo sans la déformer. La lightbox avec la classe active devient un conteneur flex, et max-width: 90vw veille à ce que la photo tienne toujours dans la fenêtre. La quatrième étape, ce sont les seuils pour les écrans plus grands :

1/* Media Queries - Tablette */
2@media (min-width: 768px) {
3    /* Navigation pour tablette */
4    .nav-toggle {
5        display: none;
6    }
7
8    .nav-menu {
9        position: static;
10        display: flex;
11        flex-direction: row;
12        width: auto;
13    }
14
15    .nav-menu li {
16        padding: 0 1rem;
17    }
18
19    /* Hero pour tablette */
20    .hero {
21        background-image: url('img/hero-tablet.jpg');
22    }
23
24    /* Galerie - 2 colonnes */
25    .gallery {
26        grid-template-columns: repeat(2, 1fr);
27    }
28}
29
30/* Media Queries - Desktop */
31@media (min-width: 1024px) {
32    /* Hero pour desktop */
33    .hero {
34        background-image: url('img/hero-desktop.jpg');
35    }
36
37    /* Galerie - 3 colonnes */
38    .gallery {
39        grid-template-columns: repeat(3, 1fr);
40        gap: 1.5rem;
41    }
42
43    /* Effets au survol uniquement sur desktop */
44    .gallery-overlay {
45        opacity: 0;
46        transform: translateY(0);
47        background: var(--overlay-dark);
48    }
49
50    .gallery-item:hover .gallery-overlay {
51        opacity: 1;
52    }
53}
54
55/* Media Queries - Grands écrans */
56@media (min-width: 1440px) {
57    .gallery {
58        grid-template-columns: repeat(4, 1fr);
59    }
60}
61
62/* Orientation paysage pour mobile */
63@media (max-width: 768px) and (orientation: landscape) {
64    .hero {
65        height: 100vw;
66    }
67
68    .hero-title {
69        font-size: 2rem;
70    }
71}
72
73/* Écrans haute densité (DPI) */
74@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
75    .hero {
76        background-image: url('img/hero-mobile@2x.jpg');
77    }
78
79    @media (min-width: 768px) {
80        .hero {
81            background-image: url('img/hero-tablet@2x.jpg');
82        }
83    }
84
85    @media (min-width: 1024px) {
86        .hero {
87            background-image: url('img/hero-desktop@2x.jpg');
88        }
89    }
90}

À partir de 768 pixels, le hamburger disparaît, le menu se place en ligne et la galerie passe à deux colonnes, puis à trois à partir de 1024 et à quatre à partir de 1440. La condition orientation: landscape repère un téléphone tourné à l'horizontale, et min-resolution: 192dpi repère les écrans à double densité de pixels, auxquels on fournit des photos en plus haute résolution.

Étape 3 : optimisation et bonnes pratiques

Optimisation des images :

L'élément picture permet au navigateur de choisir un fichier : il vérifie la condition media et s'il prend en charge le format indiqué dans type :

1<!-- Utilise l'élément picture pour les images responsives -->
2<picture>
3    <source media="(max-width: 768px)"
4            srcset="img/photo-mobile.webp"
5            type="image/webp">
6    <source media="(max-width: 768px)"
7            srcset="img/photo-mobile.jpg"
8            type="image/jpeg">
9    <source media="(max-width: 1200px)"
10            srcset="img/photo-tablet.webp"
11            type="image/webp">
12    <source media="(max-width: 1200px)"
13            srcset="img/photo-tablet.jpg"
14            type="image/jpeg">
15    <source srcset="img/photo-desktop.webp"
16            type="image/webp">
17    <img src="img/photo-desktop.jpg"
18         alt="Description de la photo"
19         loading="lazy">
20</picture>

Les navigateurs modernes téléchargeront le WebP léger, les plus anciens se rabattront sur le JPEG, et loading="lazy" retardera le téléchargement des photos situées hors de l'écran.

Styles supplémentaires pour les performances :

Pour finir, voici quelques règles pour les performances, l'accessibilité et le mode sombre :

1/* Utilise will-change pour les éléments animés */
2.gallery-item {
3    will-change: transform;
4}
5
6/* Optimisation des performances */
7.gallery-item img {
8    will-change: transform;
9    backface-visibility: hidden;
10}
11
12/* Utilise le containment CSS */
13.gallery-item {
14    contain: layout style;
15}
16
17/* Mouvement réduit (prefers-reduced-motion) */
18@media (prefers-reduced-motion: reduce) {
19    * {
20        animation-duration: 0.01ms !important;
21        animation-iteration-count: 1 !important;
22        transition-duration: 0.01ms !important;
23    }
24}
25
26/* Support du mode sombre */
27@media (prefers-color-scheme: dark) {
28    :root {
29        --primary-color: #fff;
30        --secondary-color: #1a1a1a;
31        --text-light: #333;
32    }
33
34    body {
35        background-color: #1a1a1a;
36        color: #fff;
37    }
38}

contain limite les recalculs à une seule vignette, prefers-reduced-motion raccourcit les animations pour les personnes qui ont désactivé les mouvements dans leur système, et prefers-color-scheme: dark active les couleurs sombres.

Étape 4 : une grille Grid sans media queries

La galerie utilise CSS Grid, que tu découvriras en détail dans le lieu qui lui est consacré. grid-template-columns: 1fr 1fr 1fr crée trois colonnes égales, car fr représente une fraction de l'espace libre, et repeat(3, 1fr) est la même écriture en version abrégée. Grid sait aussi choisir tout seul le nombre de colonnes :

1.gallery {
2  display: grid;
3  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
4  gap: 1rem;
5}

minmax(250px, 1fr) donne à chaque colonne au moins 250 pixels, et auto-fit en place autant que l'espace le permet, donc aucune media query n'est nécessaire. Grid dispose les éléments dans deux dimensions à la fois, alors que Flexbox travaille dans une seule, c'est pourquoi le squelette d'une page est un travail pour Grid et ses zones nommées :

1.page {
2  display: grid;
3  grid-template-columns: 200px 1fr 200px;
4  grid-template-areas:
5    "header header header"
6    "nav main aside"
7    "footer footer footer";
8}
9
10header { grid-area: header; }
11nav { grid-area: nav; }
12main { grid-area: main; }
13aside { grid-area: aside; }
14footer { grid-area: footer; }

grid-template-areas dessine le plan de la page à partir de noms, comme le plan d'un temple avec sa salle principale et ses chambres latérales, et grid-area attribue un élément à une zone. Sur un téléphone, une seule colonne avec les zones empilées les unes sous les autres suffit. Tu peux aussi calculer des largeurs avec la fonction calc(), par exemple calc(100% - 20px). Tu construirais la même galerie avec Flexbox en changeant, dans les media queries, le flex-basis des vignettes de 100% à calc(50% - 10px) puis à calc(33.33% - 14px).

Exemple de code complet

HTML (index.html) :

Par rapport à l'étape 1, le fichier complet contient une description de la page dans une balise meta, des connexions preconnect, des photos d'exemple venant de picsum.photos et le script script.js :

1<!DOCTYPE html>
2<html lang="fr">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <meta name="description" content="Portfolio de photographie de John Smith">
7    <title>John Smith - Portfolio de photographe</title>
8    <link rel="stylesheet" href="styles.css">
9    <link rel="preconnect" href="https://fonts.googleapis.com">
10    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11</head>
12<body>
13    <!-- Navigation -->
14    <nav class="navbar">
15        <div class="nav-container">
16            <div class="nav-logo">JS Photography</div>
17            <button class="nav-toggle" aria-label="Menu">
18                <span></span>
19                <span></span>
20                <span></span>
21            </button>
22            <ul class="nav-menu">
23                <li><a href="#home">Accueil</a></li>
24                <li><a href="#portfolio">Portfolio</a></li>
25                <li><a href="#about">À propos</a></li>
26                <li><a href="#contact">Contact</a></li>
27            </ul>
28        </div>
29    </nav>
30
31    <!-- Section Hero -->
32    <section id="home" class="hero">
33        <div class="hero-content">
34            <h1 class="hero-title">John Smith</h1>
35            <p class="hero-subtitle">La photographie est ma passion</p>
36            <a href="#portfolio" class="hero-button">Voir le portfolio</a>
37        </div>
38        <div class="hero-overlay"></div>
39    </section>
40
41    <!-- Section Portfolio -->
42    <section id="portfolio" class="portfolio">
43        <div class="container">
44            <h2 class="section-title">Mon portfolio</h2>
45
46            <!-- Filtres de catégorie -->
47            <div class="filter-buttons">
48                <button class="filter-btn active" data-filter="all">Tout</button>
49                <button class="filter-btn" data-filter="nature">Nature</button>
50                <button class="filter-btn" data-filter="portrait">Portraits</button>
51                <button class="filter-btn" data-filter="architecture">Architecture</button>
52            </div>
53
54            <!-- Galerie -->
55            <div class="gallery">
56                <!-- Exemples d'éléments de galerie -->
57                <div class="gallery-item" data-category="nature">
58                    <picture>
59                        <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=1">
60                        <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=1">
61                        <img src="https://picsum.photos/800/800?random=1" alt="Paysage de montagne">
62                    </picture>
63                    <div class="gallery-overlay">
64                        <h3>Paysage de montagne</h3>
65                        <p>Nature</p>
66                    </div>
67                </div>
68
69                <div class="gallery-item" data-category="portrait">
70                    <picture>
71                        <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=2">
72                        <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=2">
73                        <img src="https://picsum.photos/800/800?random=2" alt="Portrait">
74                    </picture>
75                    <div class="gallery-overlay">
76                        <h3>Portrait</h3>
77                        <p>Portraits</p>
78                    </div>
79                </div>
80
81                <div class="gallery-item" data-category="architecture">
82                    <picture>
83                        <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=3">
84                        <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=3">
85                        <img src="https://picsum.photos/800/800?random=3" alt="Architecture">
86                    </picture>
87                    <div class="gallery-overlay">
88                        <h3>Architecture moderne</h3>
89                        <p>Architecture</p>
90                    </div>
91                </div>
92
93                <div class="gallery-item" data-category="nature">
94                    <picture>
95                        <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=4">
96                        <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=4">
97                        <img src="https://picsum.photos/800/800?random=4" alt="Forêt">
98                    </picture>
99                    <div class="gallery-overlay">
100                        <h3>Sentier forestier</h3>
101                        <p>Nature</p>
102                    </div>
103                </div>
104
105                <div class="gallery-item" data-category="portrait">
106                    <picture>
107                        <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=5">
108                        <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=5">
109                        <img src="https://picsum.photos/800/800?random=5" alt="Portrait d'enfant">
110                    </picture>
111                    <div class="gallery-overlay">
112                        <h3>Joie de l'enfance</h3>
113                        <p>Portraits</p>
114                    </div>
115                </div>
116
117                <div class="gallery-item" data-category="architecture">
118                    <picture>
119                        <source media="(max-width: 768px)" srcset="https://picsum.photos/400/400?random=6">
120                        <source media="(max-width: 1200px)" srcset="https://picsum.photos/600/600?random=6">
121                        <img src="https://picsum.photos/800/800?random=6" alt="Pont">
122                    </picture>
123                    <div class="gallery-overlay">
124                        <h3>Pont au coucher du soleil</h3>
125                        <p>Architecture</p>
126                    </div>
127                </div>
128            </div>
129        </div>
130    </section>
131
132    <!-- Lightbox -->
133    <div class="lightbox" id="lightbox">
134        <span class="lightbox-close">&times;</span>
135        <img class="lightbox-content" id="lightbox-img">
136        <div class="lightbox-caption"></div>
137    </div>
138
139    <script src="script.js"></script>
140</body>
141</html>

Résumé

Ce projet illustre tous les concepts clés du design responsive :

  1. Approche Mobile-First - on part des styles mobiles
  2. Media Queries - on adapte la mise en page pour différents appareils
  3. Unités de viewport (vw, vh) - pour les sections plein écran
  4. Images responsives - élément picture avec différentes sources
  5. CSS Grid - grille de galerie responsive
  6. Flexbox - navigation flexible
  7. Clamp() - tailles de police responsives
  8. Optimisation - lazy loading, will-change, contain
  9. Accessibilité - HTML sémantique, aria-labels
  10. Fonctionnalités modernes - mode sombre, mouvement réduit

La couche HTML et CSS est prête et facile à adapter à d'autres usages, tandis que le menu, les filtres et la lightbox ont encore besoin d'un court script. Mon conseil : avant d'envoyer le projet à ton mentor, vérifie-le sur des largeurs de 320, 768, 1024 et 1440 pixels.

Souviens-toi : une galerie responsive est la cour d'un temple qui accueille aussi bien une poignée de prêtres qu'une foule de pèlerins, car sa disposition grandit avec l'écran.

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. Quelle valeur de grid-template-columns crée une grille responsive ?

  2. 2. Comment crée-t-on une CSS Grid avec trois colonnes égales ?

Voici 2 des 4 questions de cette leçon. Réponds aux autres dans le jeu.

Tâches pratiques dans le jeu

  • Clique dans l'ordre

    Place dans l'ordre le code CSS pour créer une Grid à 3 colonnes :

  • Éditeur de code

    Crée une grille responsive de dieux égyptiens avec Flexbox. HTML : <div class='pantheon'> + 6 <div class='god'>Dieu X</div> + </div>. CSS de base (mobile) : .pantheon {display: flex; flex-wrap: wrap; gap: 20px; padding: 20px;} .god {flex-basis: 100%; background: #FFD700; padding: 30px; text-align: center; border: 2px solid #8B4513;}. Tablette : @media (min-width: 768px) {.god {flex-basis: calc(50% - 10px);}}. Desktop : @media (min-width: 1024px) {.god {flex-basis: calc(33.33% - 14px);}}. Observe comment les éléments se réorganisent !

  • Tri vertical

    Place dans l'ordre la déclaration CSS Grid avec ajustement automatique des colonnes (de l'activation à la valeur minmax) :

  • Éditeur de code

    Crée une grille auto-responsive en utilisant repeat(auto-fit, minmax(250px, 1fr)).

  • Éditeur de code

    Complète le CSS : ajoute les propriétés grid-template-columns et grid-template-areas pour la vue mobile (1 colonne), puis dans une media query (min-width: 768px) définis une mise en page à 2 colonnes avec sidebar et main côte à côte.

  • Tri horizontal

    Place les éléments dans l'ordre pour créer une utilisation correcte de calc() :

  • Éditeur de code

    Crée un Holy Grail Layout avec CSS Grid. HTML : <div class='temple-layout'><header class='header'>En-tête</header><nav class='sidebar-left'>Gauche</nav><main class='main-content'>Contenu</main><aside class='sidebar-right'>Droite</aside><footer class='footer'>Pied de page</footer></div>. CSS : .temple-layout {display: grid; grid-template-areas: 'header header header' 'sidebar-left main-content sidebar-right' 'footer footer footer'; grid-template-columns: 200px 1fr 200px; grid-template-rows: auto 1fr auto; min-height: 100vh; gap: 10px;} .header {grid-area: header; background: #FFD700; padding: 20px;} .sidebar-left {grid-area: sidebar-left; background: #F4E4C1; padding: 20px;} .main-content {grid-area: main-content; background: #FFF8DC; padding: 20px;} .sidebar-right {grid-area: sidebar-right; background: #F4E4C1; padding: 20px;} .footer {grid-area: footer; background: #FFD700; padding: 20px;}.

  • Éditeur de code

    Crée une grille de cartes responsive de dieux égyptiens. HTML : <div class='cards-grid'><div class='card'><h2>Rê</h2><p>Dieu du Soleil</p></div><div class='card'><h2>Anubis</h2><p>Dieu des Morts</p></div><div class='card'><h2>Isis</h2><p>Déesse de la Magie</p></div><div class='card'><h2>Horus</h2><p>Dieu du Ciel</p></div><div class='card'><h2>Thot</h2><p>Dieu du Savoir</p></div><div class='card'><h2>Bastet</h2><p>Déesse des Chats</p></div></div>. CSS : .cards-grid {display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; padding: 20px;} .card {background: #FFD700; padding: 30px; text-align: center; border: 2px solid #8B4513; border-radius: 10px;}.

Articles utiles