Réaliser le site complet pas à pas
Le moment que vous attendiez : assembler toutes les notions du cours dans un vrai site. Vous allez construire le portfolio de Camille Morel en huit étapes, avec le code complet de chaque partie et des explications sur les choix effectués. Travaillez dans l’ordre, enregistrez et testez après chaque étape. Si vous avez préparé votre propre sujet, adaptez simplement les textes : la structure reste la même.
Étape 1 : la structure HTML
On commence uniquement par le HTML, sans style : un document sémantique, accessible et correctement hiérarchisé. Remplacez le contenu de index.html :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Camille Morel – Photographe paysages et portraits</title>
<meta name="description" content="Photographe indépendante : portraits, reportages et paysages. Découvrez mes projets et demandez un devis.">
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<a class="evitement" href="#contenu">Aller au contenu principal</a>
<header class="entete">
<p class="entete__logo">Camille Morel</p>
<nav aria-label="Navigation principale">
<ul class="menu">
<li><a href="#projets">Projets</a></li>
<li><a href="#a-propos">À propos</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main id="contenu" tabindex="-1">
<section class="hero">
<h1>Des images qui racontent vos histoires</h1>
<p>Photographe indépendante, je réalise portraits, reportages et séries de paysages.</p>
<a class="bouton" href="#contact">Demander un devis</a>
</section>
<section id="projets" class="section">
<h2>Projets</h2>
<div class="galerie">
<article class="carte">
<img class="carte__image" src="images/projets/alpes.jpg" alt="Sommets enneigés au lever du soleil" width="800" height="533">
<h3 class="carte__titre">Les Alpes en hiver</h3>
<p>Une série réalisée sur trois semaines, du lever du soleil au crépuscule.</p>
</article>
<article class="carte">
<img class="carte__image" src="images/projets/artisans.jpg" alt="Un boulanger sort des pains du four" width="800" height="533" loading="lazy">
<h3 class="carte__titre">Portraits d’artisans</h3>
<p>Rencontres dans des ateliers de la région et de leurs gestes précis.</p>
</article>
<article class="carte">
<img class="carte__image" src="images/projets/mariage.jpg" alt="Deux mariés rient sous une pluie de pétales" width="800" height="533" loading="lazy">
<h3 class="carte__titre">Mariage d’été</h3>
<p>Un reportage complet, des préparatifs jusqu’à la soirée.</p>
</article>
</div>
</section>
<section id="a-propos" class="section apropos">
<img class="apropos__portrait" src="images/portrait.jpg" alt="Camille Morel, appareil photo en main" width="400" height="400" loading="lazy">
<div>
<h2>À propos</h2>
<p>Je photographie depuis dix ans. J’aime les lumières du matin et les gens qui font bien leur métier.</p>
<p>Je me déplace dans toute la région et accepte les missions de reportage pour les associations.</p>
</div>
</section>
<section id="contact" class="section">
<h2>Me contacter</h2>
<form class="formulaire" action="#" method="post">
<p>
<label for="nom">Votre nom (obligatoire)</label>
<input type="text" id="nom" name="nom" autocomplete="name" required>
</p>
<p>
<label for="email">Votre e-mail (obligatoire)</label>
<input type="email" id="email" name="email" autocomplete="email" required>
</p>
<p>
<label for="message">Votre message (obligatoire)</label>
<textarea id="message" name="message" rows="6" required></textarea>
</p>
<button class="bouton" type="submit">Envoyer le message</button>
</form>
</section>
</main>
<footer class="pied">
<p>© Camille Morel – <a href="mentions-legales.html">Mentions légales</a></p>
</footer>
</body>
</html>
Points d’attention : un seul h1, un main, des sections avec titres, des article autonomes, des alt descriptifs, width et height sur chaque image, et du loading="lazy" uniquement sur les images qui ne sont pas visibles d’emblée. Ouvrez la page : elle est brute, mais lisible et bien ordonnée. C’est exactement ce que l’on attend d’un HTML bien écrit.
Étape 2 : variables et base du CSS
Créez css/style.css. On pose d’abord les variables, la réinitialisation et les styles de base :
/* ===== 1. VARIABLES ===== */
:root {
--couleur-principale: #1d4e5f;
--couleur-accent: #e0a96d;
--couleur-fond: #fafaf7;
--couleur-texte: #222222;
--couleur-bordure: #e3ded3;
--espace: 1rem;
--rayon: 12px;
--largeur-max: 64rem;
}
/* ===== 2. BASE ===== */
*, *::before, *::after { box-sizing: border-box; }
body {
margin: 0;
font-family: system-ui, sans-serif;
line-height: 1.6;
color: var(--couleur-texte);
background-color: var(--couleur-fond);
}
h1, h2, h3 {
font-family: Georgia, "Times New Roman", serif;
line-height: 1.2;
color: var(--couleur-principale);
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--couleur-principale); }
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible {
outline: 3px solid var(--couleur-accent);
outline-offset: 3px;
}
.section {
max-width: var(--largeur-max);
margin: 0 auto;
padding: 3rem var(--espace);
}
On a rendu les images display: block pour éviter l’espace parasite sous les images en ligne. Le focus visible est déjà défini ici : on n’aura plus à y penser.
Étape 3 : l’en-tête et la navigation
/* ===== 3. EN-TÊTE ===== */
.evitement {
position: absolute;
top: -4rem;
left: 0.5rem;
z-index: 100;
padding: 0.5rem 1rem;
background: white;
}
.evitement:focus { top: 0.5rem; }
.entete {
position: sticky;
top: 0;
z-index: 10;
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 0.75rem var(--espace);
background-color: var(--couleur-fond);
border-bottom: 1px solid var(--couleur-bordure);
}
.entete__logo {
margin: 0;
font-family: Georgia, serif;
font-size: 1.25rem;
color: var(--couleur-principale);
}
.menu {
display: flex;
gap: 1.5rem;
margin: 0;
padding: 0;
list-style: none;
}
.menu a {
display: inline-block;
padding: 0.5rem 0;
text-decoration: none;
font-weight: 600;
}
.menu a:hover { text-decoration: underline; }
@media (min-width: 40rem) {
.entete {
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
Le menu est en flex, avec des liens suffisamment hauts pour être touchés au doigt. Sur mobile, le logo est au-dessus du menu ; à partir de 40 rem, ils se placent côte à côte.
Étape 4 : la section d’accueil
/* ===== 4. HERO ===== */
.hero {
padding: 4rem var(--espace);
text-align: center;
color: white;
background: linear-gradient(135deg, var(--couleur-principale), #3b7a8c);
}
.hero h1 {
margin-top: 0;
color: white;
font-size: clamp(2rem, 1.2rem + 3vw, 3.25rem);
}
.hero p {
max-width: 40rem;
margin: 0 auto 1.5rem;
font-size: 1.125rem;
}
/* Bouton réutilisable */
.bouton {
display: inline-block;
padding: 0.75rem 1.5rem;
border: 2px solid var(--couleur-accent);
border-radius: 999px;
background-color: var(--couleur-accent);
color: #1b1b1b;
font: inherit;
font-weight: 700;
text-decoration: none;
cursor: pointer;
transition: background-color 0.2s ease, transform 0.2s ease;
}
.bouton:hover { transform: translateY(-2px); background-color: #ecbb86; }
Le titre utilise clamp() pour s’adapter sans media query. Le texte clair sur fond bleu-vert foncé offre un contraste largement suffisant, mais vérifiez-le toujours avec les outils du navigateur si vous changez les couleurs. Le bouton est un composant : il sera utilisé aussi dans le formulaire.
Étape 5 : les cartes de projets en Grid
/* ===== 5. PROJETS ===== */
.galerie {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1.5rem;
}
.carte {
overflow: hidden;
padding-bottom: 1rem;
border: 1px solid var(--couleur-bordure);
border-radius: var(--rayon);
background-color: white;
box-shadow: 0 2px 8px rgb(0 0 0 / 12%);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.carte:hover {
transform: translateY(-4px);
box-shadow: 0 8px 20px rgb(0 0 0 / 15%);
}
.carte__image {
width: 100%;
aspect-ratio: 3 / 2;
object-fit: cover;
}
.carte__titre,
.carte p { margin: 0; padding: 0 1rem; }
.carte__titre { margin-top: 1rem; }
@media (prefers-reduced-motion: reduce) {
.carte,
.bouton { transition: none; }
.carte:hover,
.bouton:hover { transform: none; }
}
La grille adaptative fait tout le travail de mise en page : une colonne sur mobile, jusqu’à trois sur grand écran. Les images ont toutes le même ratio grâce à aspect-ratio et object-fit: cover. Les effets de survol sont désactivés pour les personnes qui préfèrent réduire les animations.
Étape 6 : la section « À propos »
/* ===== 6. À PROPOS ===== */
.apropos {
display: grid;
gap: 1.5rem;
align-items: center;
}
.apropos__portrait {
width: 10rem;
height: 10rem;
object-fit: cover;
border-radius: 50%;
}
@media (min-width: 40rem) {
.apropos { grid-template-columns: auto 1fr; gap: 3rem; }
}
Sur mobile, le portrait est au-dessus du texte ; sur écran plus large, il passe à gauche. Une grille de deux colonnes, la première s’ajustant à la taille du portrait (auto) et la seconde occupant le reste (1fr).
Étape 7 : le formulaire et le pied de page
/* ===== 7. FORMULAIRE ===== */
.formulaire {
max-width: 36rem;
}
.formulaire label {
display: block;
margin-bottom: 0.25rem;
font-weight: 600;
}
.formulaire input,
.formulaire textarea {
width: 100%;
padding: 0.6rem 0.75rem;
border: 1px solid #767676;
border-radius: 8px;
font: inherit;
}
/* ===== 8. PIED DE PAGE ===== */
.pied {
padding: 1.5rem var(--espace);
text-align: center;
background-color: var(--couleur-principale);
color: white;
}
.pied a { color: white; }
La bordure des champs, d’un gris moyen, est suffisamment contrastée pour respecter le seuil de 3 pour 1 recommandé pour les éléments d’interface. Les liens du pied de page restent soulignés (comportement par défaut) pour être repérables.
Attention
L’attribut action="#" du formulaire signifie qu’aucune donnée n’est envoyée vers un traitement réel. Avant la mise en ligne, vous devrez soit utiliser la fonction de formulaire de votre hébergeur, soit un service dédié, soit remplacer le formulaire par un lien mailto:. Ne publiez pas un formulaire qui ne fait rien : les visiteurs croiraient avoir écrit.
Étape 8 : la vérification finale du responsive
À ce stade, tout le site est en place. Passez en revue les largeurs avec le mode adaptatif des outils de développement : 320 px (petit téléphone), 600 px (grand téléphone ou petite tablette), 1000 px et plus (ordinateur). Vérifiez en particulier :
- l’absence de défilement horizontal ;
- les titres qui ne se coupent pas bizarrement ;
- les cartes qui s’empilent bien en une colonne ;
- la lisibilité des textes à 200 % de zoom ;
- les cibles tactiles assez grandes.
Si un problème apparaît à une largeur précise, ajoutez une media query en min-width à cet endroit, comme vu au chapitre 4.
Astuce
Si votre résultat ne ressemble pas à ce que vous attendiez, procédez par élimination : mettez en commentaire (/* … */) la dernière règle ajoutée, rechargez, et réintroduisez-la progressivement. L’inspecteur vous indique aussi quelle règle s’applique réellement à un élément.
À vous de jouer
- Construisez le site en suivant les huit étapes, avec votre propre contenu ;
- personnalisez au moins trois choses : la palette, les polices ou le style des cartes ;
- ajoutez une quatrième carte de projet et vérifiez que la grille s’adapte ;
- créez la page
mentions-legales.htmlen réutilisant le mêmehead, l’en-tête et le pied de page.
Voir une solution
Pour la quatrième carte, ajoutez simplement un autre élément article class="carte" dans la div class="galerie" : grâce à auto-fit, la grille répartit les cartes sans autre modification. Pour personnaliser, changez les valeurs des variables dans :root : toute la page suit.
La page de mentions légales reprend la même structure :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mentions légales – Camille Morel</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header class="entete">
<p class="entete__logo"><a href="index.html">Camille Morel</a></p>
</header>
<main id="contenu">
<section class="section">
<h1>Mentions légales</h1>
<p>Éditeur du site : Camille Morel, photographe indépendante.</p>
<p>Hébergeur : à compléter selon votre hébergeur.</p>
</section>
</main>
<footer class="pied">
<p><a href="index.html">Retour à l’accueil</a></p>
</footer>
</body>
</html>
Les mentions réelles dépendent de votre situation : nous en reparlons dans la leçon suivante.
À retenir
- Construisez en couches : HTML sémantique, base et variables, en-tête, hero, galerie, à propos, formulaire et pied de page, puis responsive.
- Testez après chaque étape ; en cas de problème, revenez à la dernière version qui marchait.
- Des composants réutilisables (bouton, carte) et des variables rendent le CSS cohérent et maintenable.
- Accessibilité et performance se traitent pendant la construction : lien d’évitement, focus, contrastes,
alt,widthetheight,loading="lazy". - Un formulaire n’est utile que s’il est relié à un vrai traitement.
Votre site est prêt à être contrôlé, puis publié : c’est l’objet de la dernière leçon.