Skip to Content

Chapitre 3.1 — Pourquoi la sémantique

⏱️ TL;DR — Un élément HTML sémantique (<button>, <nav>, <h1>, <label>…) porte un sens que le navigateur traduit en rôle, focus clavier, activation et états exposés aux technologies d’assistance. Une <div> ou un <span>, eux, ne portent aucun sens : ce sont des boîtes neutres. Remplacer un natif par une <div> stylée, c’est jeter tout ce que la plateforme te donnait gratuitement — et devoir le reconstruire à la main, mal la plupart du temps. Règle de vie : choisis d’abord la bonne balise, ajoute de l’ARIA seulement quand aucun natif ne convient.

🎯 Objectifs

  • Distinguer un élément sémantique d’un élément neutre (<div>/<span>).
  • Lister ce qu’un natif apporte gratuitement : rôle, focus, clavier, états.
  • Comprendre le coût caché de la « soupe de <div> ».
  • Adopter le réflexe « la plateforme est ton amie » avant de coder un composant.

Sémantique vs soupe de <div>

Le HTML n’est pas qu’un sac de conteneurs à styler. Chaque balise déclare une intention : « ceci est un bouton », « ceci est un titre de niveau 1 », « ceci est la navigation principale ». Le navigateur lit cette intention et la publie dans l’arbre d’accessibilité (voir Partie 5), que consomment lecteurs d’écran, commandes vocales et afficheurs braille.

À l’opposé, la « soupe de <div> » (div soup) est une page où presque tout est une <div> ou un <span>. Visuellement, avec assez de CSS, ça peut ressembler à n’importe quoi. Sémantiquement, c’est le néant : ni titre, ni région, ni bouton, ni lien. Pour un utilisateur de lecteur d’écran, une telle page est une bouillie indifférenciée où plus rien ne s’annonce ni ne se navigue.

<!-- ❌ Soupe de div : rien n'est annoncé, rien n'est navigable --> <div class="header"> <div class="logo">A11yLearn</div> <div class="menu"> <div class="menu-item" onclick="go('/cours')">Cours</div> </div> </div> <div class="title-xl">Tableau de bord</div> <!-- ✅ HTML sémantique : régions, titre et lien exposés gratuitement --> <header> <a href="/">A11yLearn</a> <nav aria-label="Principale"> <a href="/cours">Cours</a> </nav> </header> <h1>Tableau de bord</h1>

Ce qu’un élément natif t’apporte — gratuitement

Prends le seul <button>. En écrivant ces sept caractères, tu obtiens sans une ligne de JavaScript :

  • Un rôle exposé : le lecteur d’écran annonce « bouton ». L’utilisateur sait que c’est actionnable.
  • Le focus clavier : l’élément entre dans l’ordre de tabulation, atteignable avec Tab.
  • L’activation clavier : Entrée et Espace déclenchent le clic, exactement comme la souris.
  • La gestion des états : disabled grise ET retire le focus ET bloque l’activation, d’un coup.
  • La sémantique de formulaire : type="submit" soumet le formulaire, type="button" non.

Refaire tout ça sur une <div> demande : role="button", tabindex="0", un gestionnaire keydown pour Entrée et Espace, la gestion de aria-disabled, la prévention du scroll sur Espace… des dizaines de lignes fragiles pour ré-obtenir ce que la balise offrait d’emblée. C’est le sens de la formule : « la plateforme est ton amie » (use the platform). Elle a déjà résolu ces problèmes ; ne les recode pas.

💡 Réflexe — Avant d’écrire une <div> interactive, pose-toi une seule question : « existe-t-il un élément HTML natif pour ça ? ». Un clic qui agit → <button>. Une navigation → <a href>. Un champ → <input>/<select>/<textarea>. Un repli/dépli → <details>/<summary>. Neuf fois sur dix, le natif existe et te fait gagner du temps et de l’accessibilité.

L’exemple frappant : <div onclick> vs <button>

C’est le cas d’école, celui qui résume toute cette partie. Deux « boutons » identiques à l’écran, deux expériences radicalement opposées.

<!-- ❌ Muet et inaccessible --> <div class="btn" onclick="sInscrire()">S'inscrire</div> <!-- ✅ Rôle, focus et clavier gratuits --> <button type="button" onclick="sInscrire()">S'inscrire</button>

Ce que le lecteur d’écran annonce dans chaque cas :

<div onclick><button>
Annonce« S’inscrire » (texte brut)« S’inscrire, bouton »
Atteignable au clavier ?Non (hors de l’ordre de tabulation)Oui (Tab)
Activable au clavier ?Non (ni Entrée ni Espace)Oui (Entrée / Espace)
État disabled géré ?NonOui, nativement

Le premier existe pour la souris uniquement. Un utilisateur au clavier ou au lecteur d’écran ne peut littéralement pas s’inscrire. Le second marche pour tout le monde — et tu as tapé moins de code.

Côté utilisateur — Une personne aveugle qui tabule dans ta page ne « voit » que les éléments focusables et leurs rôles. Le <div onclick> est pour elle invisible : le focus saute par-dessus, comme s’il n’existait pas. Elle ne saura même pas qu’un bouton « S’inscrire » est là. Le <button>, lui, s’annonce « S’inscrire, bouton » et s’active — le même pixel à l’écran, mais un mur d’un côté et une porte de l’autre.

Le coût caché du tout-<div>

Choisir la <div> par défaut n’est pas « neutre, on verra plus tard ». C’est contracter une dette immédiate :

  • Dette d’accessibilité : rôles, clavier et états à recoder un par un, avec de l’ARIA (Partie 6) — plus de code, plus de bugs, plus de tests.
  • Dette de robustesse : ton composant maison suit ta logique, pas la convention du navigateur ; il casse sur des cas que le natif gère déjà (focus, disabled, formulaire).
  • Dette de maintenance : chaque nouveau dév doit comprendre ton faux-bouton au lieu de lire un <button> évident.

Le HTML natif, à l’inverse, est testé par des milliards d’utilisateurs, cohérent entre navigateurs et technologies d’assistance, et gratuit. La sémantique n’est pas une contrainte esthétique : c’est le choix qui coûte le moins tout en accessibilisant par défaut.

🧭 Sur A11yLearn — Le premier audit d’A11yLearn révèle une barre de navigation entièrement en <div class="nav-item" onclick> et des cartes de cours « cliquables » en <div>. Rien n’est atteignable au clavier, rien ne s’annonce. Notre première correction n’ajoute aucune ligne d’ARIA : on remplace les <div> par des <a href> et des <button>. D’un coup, la navigation clavier fonctionne et le lecteur d’écran annonce liens et boutons. La leçon fondatrice du cours : commencer par la bonne balise, pas par de l’ARIA.

📚 Aller plus loin — Ce chapitre touche deux points centraux du référentiel : le critère 4.1.2 (Nom, rôle et valeur) — chaque composant d’interface doit exposer son nom, son rôle et son état aux technologies d’assistance — et la première règle d’ARIA : « si un élément HTML natif fournit déjà la sémantique et le comportement voulus, utilise-le plutôt que de le réinventer en ARIA ». On approfondit l’arbre d’accessibilité en Partie 5 et ARIA en Partie 6.

✏️ Exercices

Exercice 1 — Nomme ce qui est perdu. On te donne <span class="button" onclick="valider()">Valider</span>. Cite trois choses qu’un <button> natif apporterait et que ce <span> n’a pas.

✅ Solution

Au moins : (1) le rôle « bouton » annoncé par le lecteur d’écran ; (2) le focus clavier (le <span> n’est pas dans l’ordre de tabulation, donc inatteignable au clavier) ; (3) l’activation clavier par Entrée/Espace. On peut ajouter la gestion native de disabled et l’intégration au formulaire (type="submit"). Tout cela devrait sinon être recodé à la main avec role, tabindex et un gestionnaire keydown.

Exercice 2 — Traduis en sémantique. Réécris ce fragment en HTML sémantique sans changer le rendu attendu.

<div class="card" onclick="ouvrir('/cours/1')"> <div class="card-title">React accessible</div> <div class="card-cta" onclick="sInscrire(1)">S'inscrire</div> </div>

✅ Solution

La carte mène vers une page → c’est un lien. « S’inscrire » déclenche une action sur place → c’est un bouton. On évite d’imbriquer un bouton dans un lien (interdit et ambigu) : on met le lien sur le titre et le bouton à côté.

<article class="card"> <h3><a href="/cours/1">React accessible</a></h3> <button type="button" onclick="sInscrire(1)">S'inscrire</button> </article>

Le titre devient un vrai titre navigable, le lien un vrai lien, le bouton un vrai bouton — clavier et annonces gratuits.

🧠 Quiz de révision

1. Que veut dire « la soupe de div » et pourquoi est-ce un problème d’accessibilité ?

Une page faite presque exclusivement de <div>/<span>. Ces éléments sont neutres : ils n’exposent ni rôle, ni titre, ni région, ni comportement clavier. Pour un utilisateur de lecteur d’écran, plus rien ne s’annonce ni ne se navigue — l’information sémantique a disparu.

2. Cite trois choses qu’un <button> natif apporte gratuitement.

Parmi : le rôle « bouton » annoncé, le focus clavier (ordre de tabulation), l’activation par Entrée/Espace, la gestion native de l’état disabled, et la sémantique de formulaire (type="submit"/"button"). Tout cela sans JavaScript.

3. Que signifie « la plateforme est ton amie » ?

Que le navigateur a déjà résolu les problèmes de rôle, focus, clavier et états dans ses éléments natifs. Plutôt que de recoder ce comportement sur des <div>, on utilise l’élément HTML prévu pour ça — c’est moins de code, plus robuste et accessible par défaut.

4. Pourquoi un <div onclick> est-il inaccessible au clavier ?

Parce qu’une <div> n’est pas dans l’ordre de tabulation par défaut (pas focusable) et n’a aucun gestionnaire clavier : ni Entrée ni Espace ne l’activent. Le focus saute par-dessus, l’élément est invisible pour qui n’utilise pas la souris.

5. Quel est le bon ordre : HTML natif ou ARIA d’abord ?

HTML natif d’abord. La première règle d’ARIA est de préférer un élément natif quand il existe. ARIA ne fait rien (ni focus, ni clavier) : il ne fait que décrire. On ne l’ajoute que lorsqu’aucun élément natif ne couvre le besoin.


Chapitre suivant : Structure & landmarks — comment découper une page en régions navigables au lecteur d’écran.

Last updated on