Skip to Content
FrontendHTML sémantique

HTML sémantique — Guide pratique

Structurer une page avec les bons éléments HTML améliore l’accessibilité, le référencement et la maintenabilité du code. Cette page couvre les éléments sémantiques, les structures typiques et les pièges courants.

Cette page est un complément à Frontend (vue d’ensemble HTML) et à Motifs de mise en page (mise en page CSS). Elle se concentre sur le choix et l’agencement des balises sémantiques.


Les éléments sémantiques — quand utiliser quoi

Structure de page

ÉlémentRôleContraintes
<header>En-tête d’une section ou de la pagePeut contenir logo, titre, navigation. Possiblement plusieurs sur une page (un par section).
<nav>Groupe de liens de navigationPas nécessaire pour tous les liens — réserver aux navigations principales (menu, pagination, fil d’Ariane).
<main>Contenu principal unique de la pageUn seul par page. Ne doit pas contenir d’en-tête, de navigation ou de footer global.
<section>Regroupement thématique de contenuDoit avoir un titre (<h1><h6>). Pas un simple conteneur de style.
<article>Contenu autonome, redistribuableUn billet de blog, un commentaire, une carte produit — peut être partagé indépendamment.
<aside>Contenu secondaire, lié au principalSidebar, publicités, glossaire — peut être lu indépendamment du contexte principal.
<footer>Pied de page ou de sectionCopyright, liens légaux, meta-liens. Possiblement plusieurs (un par section).

Règle simple : si un groupe d’éléments a un titre et un sujet unique, c’est une <section>. Si le contenu a un sens propre sans le reste de la page, c’est un <article>.

Autres éléments utiles

ÉlémentRôle
<figure> + <figcaption>Illustration autonome avec légende. Peut être déplacée sans perdre de sens.
<details> + <summary>Accordion native, sans JavaScript. Idéal pour FAQ, spoilers, expansion.
<time>Date/heure machine-lisible. Attributs : datetime="YYYY-MM-DD".
<mark>Texte mis en évidence (recherche, annotation).
<address>Informations de contact. Non pas une adresse postale dans du texte, mais le bloc contact.
<blockquote>Citation longue. L’<aside> pour citation hors contexte, le <blockquote> pour citation dans le texte.
<dialog>Fenêtre modale native (attribut open pour afficher).

Structures typiques

1. Page complète

<body> <header> <nav>…</nav> </header> <main> <section>…</section> <article>…</article> </main> <aside>…</aside> <footer>…</footer> </body>

Piège : utiliser &lt;div id="main"&gt; à la place de &lt;main&gt;. Les lecteurs d’écran utilisent &lt;main&gt; pour le raccourci « sauter au contenu principal ». Une &lt;div&gt; ne donne pas cet accès.

2. Article + sidebar (blog, article)

<main> <article> <header> <h1>Titre de l'article</h1> <time datetime="2026-07-05">5 juillet 2026</time> </header> <section> <p>Corps de l'article…</p> </section> <footer> <p>Par <address>Jean Dupont</address></p> </footer> </article> <aside> <section> <h2>Articles récents</h2> <ul>…</ul> </section> </aside> </main>

Piège : mettre le &lt;aside&gt; à l’intérieur du &lt;article&gt;. L’aside doit être un frère de l’article, pas un enfant. Le mettre à l’intérieur signifierait que la sidebar fait partie du contenu de l’article.

3. Navigation avec fil d’Ariane et menu secondaire

<body> <header> <nav aria-label="Fil d'Ariane"> <ol> <li><a href="/">Accueil</a></li> <li><a href="/docs">Documentation</a></li> <li><span aria-current="page">Guide</span></li> </ol> </nav> <nav aria-label="Navigation principale"> <ul>…</ul> </nav> </header> </body>

Piège : avoir plusieurs &lt;nav&gt; sans aria-label. Un lecteur d’écran ne peut pas distinguer le menu principal de la pagination. Toujours ajouter un aria-label distinct si la page contient plusieurs navigations.

<footer> <nav aria-label="Liens légaux"> <ul> <li><a href="/mentions-legales">Mentions légales</a></li> <li><a href="/confidentialite">Confidentialité</a></li> </ul> </nav> <p>&copy; 2026 Entreprise</p> <address>Contact : <a href="mailto:contact@example.com">contact@example.com</a></address> </footer>

5. Section avec figure et légende

<section> <h2>Installation</h2> <p>Exécution de la commande :</p> <figure> <pre><code>npm install mon-paquet</code></pre> <figcaption>Figure 1. Commande d'installation du paquet.</figcaption> </figure> </section>

6. Accordion natif avec &lt;details&gt;

<details> <summary>Qu'est-ce que le HTML sémantique ?</summary> <p>C'est utiliser les balises HTML pour exprimer le sens du contenu…</p> </details> <details> <summary>Avantages pour le SEO ?</summary> <p>Les moteurs de recherche comprennent mieux la structure…</p> </details>

Piège : utiliser &lt;details&gt; pour du contenu qui doit être visible par défaut. L’élément est conçu pour être replié par défaut. Retirer l’attribut open pour cacher, ou utiliser un pattern CSS/JS si le comportement doit être différent.


Accessibilité (a11y) — les 5 points essentiels

1. Hiérarchie des titres

<h1> Titre de la page (UN SEUL par page) </h1> <h2> Section principale </h2> <h3> Sous-section </h3> <h2> Section suivante </h2> <h3> Sous-section </h3>

Piège : sauter des niveaux (&lt;h1&gt;&lt;h3&gt; sans &lt;h2&gt;). Les lecteurs d’écran permettent de naviguer par titre. Un saut de niveau casse le parcours.

Piège : utiliser &lt;h1&gt; pour le titre du site dans le header ET un autre &lt;h1&gt; pour le titre de la page. Résultat : deux &lt;h1&gt; dans la page. Utiliser &lt;h2&gt; pour le titre du site dans le header, &lt;h1&gt; uniquement pour le titre de la page.

2. aria-label et aria-labelledby

<!-- Libeller un nav sans texte visible --> <nav aria-label="Réseaux sociaux">…</nav> <!-- Raccourcis clavier --> <button aria-label="Fermer">✕</button> <!-- Lier une légende à sa figure --> <figure aria-labelledby="fig-1"> <img src="graphique.png" alt=""> <figcaption id="fig-1">Graphique des ventes 2026</figcaption> </figure>

Piège : utiliser aria-label sur un &lt;a&gt; dont le texte visible dit déjà la même chose. Double lecture redondante. Garder aria-label uniquement quand le texte visible ne transmet pas suffisamment d’information.

3. role — quand et pourquoi

Les rôles ARIA sont le plus souvent inutiles car les éléments sémantiques les portent déjà :

ÉlémentRôle implicite
&lt;nav&gt;role="navigation"
&lt;main&gt;role="main"
&lt;article&gt;role="article"
&lt;aside&gt;role="complementary"
&lt;header&gt;role="banner"
&lt;footer&gt;role="contentinfo"
&lt;button&gt;role="button"
&lt;input type="text"&gt;role="textbox"

Règle ARIA n°1 : ne jamais utiliser role si un élément sémantique standard fait le travail. L’exception est l’utilisation de &lt;div&gt; ou &lt;span&gt; pour un composant interactif (ex : un div qui imite un bouton → ajouter role="button" + gestion clavier).

Un lien caché en premier dans le &lt;body&gt; permet de passer directement au contenu principal :

<body> <a href="#main-content" class="skip-link">Aller au contenu principal</a> <header>…</header> <main id="main-content">…</main> </body>
.skip-link { position: absolute; top: -100px; left: 0; z-index: 9999; padding: 8px 16px; background: #2563eb; color: white; } .skip-link:focus { top: 0; }

5. Textes alternatifs et alt

<!-- Image informative : décrire le contenu --> <img src="diagramme-archi.png" alt="Architecture microservices avec 3 services communiquant via un bus événementiel"> <!-- Image décorative : alt vide --> <img src="separator.png" alt=""> <!-- Image ignorée du lecteur d'écran (pure décoration) --> <img src="decor.png" role="presentation" alt="">

Piège : mettre une description longue dans alt pour les images décoratives. Le lecteur d’écran lit tout haut à chaque chargement de page. Les images purement esthétiques doivent avoir alt="".


Pièges récurrents

PiègeSymptômeCorrection
&lt;div class="nav"&gt; à la place de &lt;nav&gt;Pas de raccourci lecteur d’écranRemplacer par &lt;nav&gt;
Plusieurs &lt;main&gt; sur la pageConfusion pour les lecteurs d’écranUn seul &lt;main&gt; par page ; utiliser &lt;section&gt; pour les autres
&lt;div&gt; cliquable sans roleFocus invisible, inaccessible au clavierUtiliser &lt;button&gt; ou ajouter role="button" tabindex="0" + gestion Enter/Space
alt manquant sur &lt;img&gt;Erreur WCAG 1.1.1Toujours ajouter alt, même vide pour décorative
&lt;section&gt; sans titreNon significatif, confond avec un &lt;div&gt;Ajouter un &lt;h2&gt;&lt;h6&gt; ou utiliser &lt;div&gt;
Bouton sans texte accessibleClic impossible via lecteur d’écranAjouter un texte, ou aria-label
&lt;audio&gt; / &lt;video&gt; sans sous-titresNon accessible aux malentendantsAjouter &lt;track kind="captions"&gt;
tabindex positif sur des &lt;div&gt;Ordre de tabulation casséUtiliser tabindex="0" au maximum ; corriger l’ordre si besoin
&lt;span&gt; pour styliser du textePas de sémantique ajoutéeUtiliser &lt;strong&gt; (important), &lt;em&gt; (emphase), &lt;mark&gt; (surligné)
&lt;h1&gt; dans le header + &lt;h1&gt; dans le mainDeux titres principauxHeader : &lt;h2&gt; pour le nom du site, main : &lt;h1&gt; pour le titre de page

Checklist avant livraison

  • Un seul &lt;h1&gt; par page
  • Au moins un &lt;main&gt; contenant le contenu principal
  • Chaque &lt;nav&gt; a un aria-label distinct
  • Tous les &lt;img&gt; ont un attribut alt
  • Pas de saut de niveau dans la hiérarchie des titres
  • Les éléments interactifs (div/span cliquables) ont role, tabindex et gestion clavier
  • Un &lt;details&gt; n’a pas l’attribut open par défaut (sauf intention)
  • Un skip link existe en premier dans le &lt;body&gt;
  • &lt;audio&gt; / &lt;video&gt; ont des sous-titres si pertinents

Arbre de décision rapide

Nouvelle page HTML à structurer ? ├─ Quelle est la structure globale ? │ ├─ Header + nav + contenu + footer → éléments ① (voir § Structures typiques) │ └─ Une seule région principale → <main> seul, pas d'aside ├─ Le contenu est-il autonome ? │ ├─ Oui (article, carte, post) → <article> │ └─ Non (regroupement thématique) → <section> ├─ Besoin d'une navigation ? │ ├─ Menu principal → <nav aria-label="Navigation principale"> │ ├─ Pagination → <nav aria-label="Pagination"> │ ├─ Fil d'Ariane → <nav aria-label="Fil d'Ariane"> │ └─ Liens sociaux (inline) → <div> suffisant (pas une navigation) ├─ Besoin d'un contenu secondaire ? │ ├─ Sidebar, publicités → <aside> │ └─ Citation dans le texte → <blockquote> └─ Besoin de cacher/déplier du contenu ? └─ Oui → <details> + <summary> (pas de JS)

Référence : MDN HTML sémantique .