Structurer la page avec des éléments natifs
Objectif : Organiser le tableau de bord avec des régions et des titres qui rendent sa structure navigable.
Quand une page ne présente ses zones qu’avec des conteneurs génériques, les personnes qui naviguent au clavier ou avec un lecteur d’écran doivent parcourir davantage de contenu pour comprendre où elles se trouvent. Une structure HTML sémantique fournit des repères nommés et des titres consultables, sans dépendre de la mise en forme.
Dans cette leçon, vous organisez le tableau de bord des dépenses en zones cohérentes : un en-tête, une navigation, un contenu principal et des sections consacrées au récapitulatif, à la saisie et à la liste. Vous ne modifiez pas le comportement des formulaires ni des filtres ; ces interactions seront traitées dans les leçons suivantes.
Choisir des éléments qui décrivent leur rôle
Utilisez header pour l’en-tête de la page, nav pour ses liens de navigation et main pour son contenu principal. Les éléments section regroupent des contenus ayant un thème commun ; chacun reçoit un titre identifiable, notamment avec aria-labelledby. Ces éléments natifs donnent une signification aux zones que des éléments génériques ne communiquent pas à eux seuls.
Voici la structure complète de la page à utiliser comme repère. Les valeurs entre accolades du contrat React sont ici remplacées par des exemples statiques pour rendre le document HTML directement lisible ; dans l’application, elles restent alimentées par les composants et les données déjà en place. Les liens de navigation pointent vers les identifiants des sections correspondantes.
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Tableau de bord des dépenses</title>
<link rel="stylesheet" href="src/styles/style.css" />
</head>
<body>
<div class="atelier-app">
<header class="atelier-entete">
<h1>Tableau de bord des dépenses</h1>
<nav class="atelier-navigation" aria-label="Navigation principale">
<a href="#recapitulatif">Récapitulatif</a>
<a href="#saisie">Ajouter une dépense</a>
<a href="#depenses">Dépenses</a>
</nav>
</header>
<main class="atelier-principal">
<section id="recapitulatif" class="atelier-recapitulatif" aria-labelledby="titre-recapitulatif">
<h2 id="titre-recapitulatif">Récapitulatif mensuel</h2>
<label for="mois">Mois</label>
<input id="mois" name="mois" type="month" value="2025-03" />
<p>Total du mois : <strong class="atelier-recapitulatif__montant">125,50 €</strong></p>
<p>Nombre de dépenses : 2</p>
<ul aria-label="Totaux par catégorie">
<li>Alimentation : 80,50 €</li>
<li>Transport : 45,00 €</li>
</ul>
</section>
<section id="saisie" class="atelier-depense" aria-labelledby="titre-saisie">
<h2 id="titre-saisie">Ajouter une dépense</h2>
<form class="atelier-depense__formulaire">
<label for="description">Description</label>
<input id="description" name="description" required />
<label for="montant">Montant</label>
<input id="montant" name="montant" type="number" min="0" step="0.01" required />
<label for="categorie">Catégorie</label>
<select id="categorie" name="categorie" required>
<option value="alimentation">Alimentation</option>
<option value="transport">Transport</option>
</select>
<label for="date">Date</label>
<input id="date" name="date" type="date" required />
<button type="submit">Ajouter la dépense</button>
</form>
</section>
<section id="depenses" class="atelier-liste" aria-labelledby="titre-depenses">
<h2 id="titre-depenses">Dépenses</h2>
<div class="atelier-filtres" aria-label="Filtres des dépenses">
<label for="filtre-categorie">Catégorie</label>
<select id="filtre-categorie" class="atelier-filtres__selecteur">
<option value="toutes">Toutes les catégories</option>
<option value="alimentation">Alimentation</option>
<option value="transport">Transport</option>
</select>
<label for="filtre-recherche">Recherche</label>
<input id="filtre-recherche" type="search" />
</div>
<table class="atelier-liste__tableau">
<caption>Liste des dépenses filtrées</caption>
<thead><tr><th scope="col">Date</th><th scope="col">Description</th><th scope="col">Catégorie</th><th scope="col">Montant</th><th scope="col">Actions</th></tr></thead>
<tbody>
<tr><td>2025-03-04</td><td>Courses</td><td>Alimentation</td><td>80,50 €</td><td><button type="button" aria-label="Supprimer Courses">Supprimer</button></td></tr>
<tr><td>2025-03-06</td><td>Bus</td><td>Transport</td><td>45,00 €</td><td><button type="button" aria-label="Supprimer Bus">Supprimer</button></td></tr>
</tbody>
</table>
<p class="atelier-annonce" role="status" aria-live="polite"></p>
</section>
</main>
</div>
</body>
</html>La page possède un seul h1, son titre général. Les titres h2 nomment les trois sections principales et permettent de passer directement d’une zone à une autre avec les commandes de navigation par titres d’un lecteur d’écran. Gardez cet ordre logique : ne choisissez pas un niveau de titre uniquement pour obtenir une taille de texte particulière.
Faire correspondre les repères à leur présentation
Les classes du contrat restent des hooks de présentation : elles ne remplacent pas les éléments sémantiques. Vérifiez aussi que chaque classe utilisée dans le HTML reçoit une règle dans l’unique feuille de style. Les règles ci-dessous couvrent les classes de l’en-tête, de la navigation, du contenu principal, du récapitulatif et de la saisie ; elles utilisent uniquement les variables de présentation déclarées par le projet.
.atelier-app {
color: var(--atelier-couleur-texte);
background: var(--atelier-couleur-fond);
font-family: var(--atelier-police);
font-size: var(--atelier-taille-texte);
}
.atelier-entete {
padding: var(--atelier-espace-moyen);
border-bottom: 1px solid var(--atelier-couleur-bordure);
}
.atelier-navigation {
display: flex;
flex-wrap: wrap;
gap: var(--atelier-espace-moyen);
}
.atelier-navigation a {
color: var(--atelier-couleur-accent);
}
.atelier-principal {
display: grid;
gap: var(--atelier-espace-grand);
padding: var(--atelier-espace-grand);
}
.atelier-recapitulatif,
.atelier-depense {
padding: var(--atelier-espace-moyen);
border: 1px solid var(--atelier-couleur-bordure);
border-radius: var(--atelier-rayon);
}
.atelier-recapitulatif__montant {
color: var(--atelier-couleur-accent);
}
.atelier-depense__formulaire {
display: grid;
gap: var(--atelier-espace-petit);
}Aperçu appliqué au document HTML de cette leçon : la règle CSS est injectée dans la page pour voir son effet réel.
Dans les composants React existants, la même organisation s’exprime avec className et des titres rendus par les composants concernés ; le balisage n’impose pas de déplacer la logique ou l’état. Pour les zones dont le titre est visible, reliez l’identifiant du titre à la section avec aria-labelledby, comme dans le repère. N’ajoutez un nom accessible distinct que lorsque le texte visible ne suffit pas à identifier le rôle de la zone.
Contrôlez la structure en masquant mentalement les styles : le titre de page doit rester identifiable, les liens doivent mener aux sections et chaque section doit annoncer son sujet. Ce contrôle révèle les problèmes de hiérarchie que des espacements ou une typographie ne peuvent pas corriger. Les tableaux conservent leurs en-têtes, et les champs gardent leurs libellés associés conformément au squelette de référence.
À retenir
- Employez les éléments natifs
header,nav,mainetsectionselon leur rôle. - Donnez un titre pertinent à chaque section et reliez-le avec
aria-labelledby. - Respectez la hiérarchie des titres : un
h1général, puis desh2pour les zones principales. - Vérifiez que les classes utilisées ont leurs règles dans la feuille de style prévue, sans ajouter de classes au contrat.
Dans la prochaine leçon, vous rendrez le formulaire de dépense plus explicite pour les personnes qui utilisent des technologies d’assistance.