Accessibilité web : penser un site dès la page blanche
Quand on construit un site web, on pense souvent à ce qui va “rendre bien” : les couleurs, les animations, l’effet d’ensemble. On pense moins à ceux qui ne pourront jamais le visiter. Pas parce qu’ils n’ont pas envie, mais parce que le chemin est barré : trop étroit, sans échappatoire, sans indication claire. Beaucoup n’y verront… rien. D’autres n’utiliseront jamais de souris. Certains ne comprendront même pas qu’un bouton est un bouton.
L’accessibilité, ce n’est pas une option : c’est une base invisible, mais essentielle.
Alors, on a voulu repartir de zéro. Depuis une page blanche, comme celle qu’on ouvre dans Visual Studio Code ou Sublime Text. Pas de CMS, pas de framework. Juste du HTML, du CSS, du JavaScript. Et une seule question : comment faire, dès le départ, pour que notre site soit accessible, utilisable, compréhensible, pour toutes et tous ?
Poser les bases : structure HTML claire et lisible
Quand on démarre une page web, on pense souvent à ce qui s’affichera… mais rarement à ce que les utilisateurs ne verront pas. Pourtant, un lecteur d’écran ou un robot d’indexation ne « voit » que la structure HTML. Si cette base est confuse, l’expérience l’est aussi. C’est pourquoi tout commence par une structure propre, hiérarchique et lisible.
Prenons un exemple de page de réservation pour une conférence :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Réserver une place – Conférence</title>
</head>
<body>
<header>
<h1>Conférence "Demain, le web"</h1>
<nav>
<ul>
<li><a href="#infos">Infos</a></li>
<li><a href="#billets">Billetterie</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main>
<section id="infos">
<h2>Informations pratiques</h2>
<p>Lieu, horaires, accessibilité physique...</p>
</section>
<section id="billets">
<h2>Réserver votre place</h2>
<p>Formulaire à venir...</p>
</section>
<aside>
<h3>COVID et distanciation</h3>
<p>Les places sont limitées pour garantir la sécurité.</p>
</aside>
</main>
<footer>
<p>© 2025 – Puce & Média</p>
</footer>
</body>
</html>
Pourquoi c’est utile ?
- Le
lang="fr"
permet aux lecteurs vocaux de lire correctement. - Les balises
<header>
,<nav>
,<main>
,<section>
,<aside>
,<footer>
donnent une structure logique. - La hiérarchie des titres (
<h1>
,<h2>
,<h3>
) rend la navigation claire, même sans CSS.
Un utilisateur aveugle, avec un lecteur comme NVDA, pourra parcourir les sections par titre ou sauter d’un bloc à l’autre via les repères sémantiques. Un moteur de recherche comprendra aussi mieux le contenu.
À tester à ce stade :
- WAVE Web Accessibility Evaluation Tool
Collez ce code dans un fichier HTML local, ouvrez-le dans votre navigateur, et collez son URL (viafile://
ou un petit serveur local) dans WAVE pour tester l’arborescence. - Inspecteur navigateur
Dans Firefox ou Chrome, activez le panneau Accessibilité (onglet Accessibility ou A11y tree) pour vérifier les rôles, régions et niveaux de titres.

Formulaires accessibles : penser le lien entre champs et libellés
Remplir un formulaire, c’est simple… si on voit ce qu’il faut faire. Mais que se passe-t-il pour une personne non voyante, ou pour quelqu’un utilisant un lecteur d’écran ? Si chaque champ n’est pas correctement lié à son libellé, le formulaire devient un piège invisible.
Imaginons ici le formulaire de réservation de notre conférence, avec un nom, un e-mail, une option de tarif réduit, et un bouton d’envoi :
<form action="traitement.php" method="post">
<fieldset>
<legend>Vos informations</legend>
<label for="nom">Nom complet :</label>
<input type="text" id="nom" name="nom" required>
<label for="email">Adresse e-mail :</label>
<input type="email" id="email" name="email" required aria-describedby="info-mail">
<p id="info-mail">Nous n’utiliserons votre e-mail que pour vous envoyer votre billet.</p>
<label>
<input type="checkbox" name="reduction" value="oui">
Tarif réduit (étudiant, demandeur d’emploi)
</label>
</fieldset>
<button type="submit">Valider la réservation</button>
</form>
Pourquoi c’est utile ?
- Chaque
<input>
est lié à un<label>
clair. Cela permet au lecteur d’écran de lire « Nom complet : zone de saisie » au bon moment. - La zone email utilise
aria-describedby
pour fournir une explication complémentaire audible. - Le bouton d’envoi est un
<button>
, pas un lien déguisé ou une image.
À tester à ce stade :
- Naviguez au clavier : appuyez sur Tab dans l’ordre logique : nom → mail → case à cocher → bouton. Rien ne doit sauter ou piéger l’utilisateur.
- Utilisez un lecteur vocal : sous Windows, testez avec NVDA (gratuit) ; sur Mac, activez VoiceOver (
Cmd + F5
). - Test WAVE : vérifie si les champs ont des libellés explicites et les rôles associés.

Ce n’est pas plus de code. C’est juste du code plus lisible, plus fiable, et qui ne crée pas d’obstacle pour des personnes qui ont besoin du web comme tout le monde.
Et les CAPTCHA ?
Les CAPTCHA sont conçus pour bloquer les robots… mais ils bloquent aussi les humains qui utilisent des lecteurs d’écran, des synthèses vocales, ou qui ont simplement des difficultés cognitives. Il existe des alternatives bien plus accessibles, comme les champs invisibles (honeypots), les validations différées, ou des logiques de temps de saisie. Nous en détaillons plusieurs dans notre article dédié : Protection de base pour un formulaire, cependant si un captcha est vraiment nécessaire :
<label for="captcha">Recopiez les caractères affichés :</label>
<img src="captcha.php" alt="Code de sécurité" aria-describedby="captcha-explication">
<input type="text" name="captcha" id="captcha" required>
<p id="captcha-explication">
Si vous ne pouvez pas lire ce code, <a href="/contact.html">contactez-nous directement</a>.
</p>
Conseils :
- Toujours fournir un
alt
explicite pour l’image du CAPTCHA. - Ajouter un lien ou un canal alternatif en cas d’échec.
- Tester si le champ est focusable, navigable au clavier et lisible au lecteur d’écran.
Voici un exemple de formulaire HTML intégrant Google reCAPTCHA v2 avec des considérations d’accessibilité :
<form action="traitement.php" method="post">
<label for="email">Adresse e-mail :</label>
<input type="email" id="email" name="email" required>
<div class="g-recaptcha" data-sitekey="VOTRE_CLE_SITE"></div>
<button type="submit">Envoyer</button>
</form>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
Dans cet exemple, le widget reCAPTCHA v2 est intégré via une balise <div>
avec la classe g-recaptcha
et l’attribut data-sitekey
contenant votre clé de site fournie par Google. Le script JavaScript nécessaire est chargé de manière asynchrone pour ne pas bloquer le rendu de la page.
Pour plus d’informations sur l’intégration et la personnalisation de reCAPTCHA v2, vous pouvez consulter la documentation officielle de Google : Documentation reCAPTCHA v2 – Google Developers. Cette documentation fournit des détails sur les différentes options de configuration, telles que le thème, la taille du widget, la langue, ainsi que des instructions pour la validation côté serveur.
Navigation au clavier : indispensable pour tous
Naviguer sans souris, ce n’est pas qu’une question de handicap moteur ou de cécité. C’est aussi une réalité pour tous ceux qui utilisent un clavier externe, une commande vocale ou une technologie d’assistance. Un site accessible doit donc fonctionner 100 % au clavier.
Prenons un menu de navigation simplifié. Il doit permettre de passer d’un lien à l’autre avec la touche Tab, et indiquer visuellement où l’on est.
<nav>
<ul>
<li><a href="#infos">Infos pratiques</a></li>
<li><a href="#billets">Réserver</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
Et voici un extrait CSS pour améliorer la visibilité du focus clavier :
Pourquoi c’est utile ?
- Par défaut, le focus clavier peut être invisible ou peu lisible.
- Une personne en situation de handicap moteur (ex. : sclérose en plaques) peut naviguer par tabulation uniquement.
- Si vous supprimez
outline
en CSS sans alternative, vous cassez l’accessibilité.
À tester à ce stade :
- Tabuler dans la page : la touche Tab doit faire avancer dans l’ordre logique : menu → contenu → formulaire → pied de page.
- Touche Shift+Tab : elle permet de revenir en arrière ; testez sa cohérence.
- Inspecteur navigateur : dans Chrome ou Firefox, vérifiez que chaque élément reçoit bien un
focus
, et que la classe CSS ne masque pas son contour.

Astuce : n’utilisez jamais tabindex="-1"
sur des éléments de navigation, sauf si vous gérez manuellement le focus dans des composants dynamiques (on y reviendra dans la section suivante).
Et le tabindex
, alors ?
Il est possible de modifier l’ordre naturel de tabulation avec l’attribut tabindex
:
<input type="text" name="nom" tabindex="1">
<input type="text" name="email" tabindex="2">
Mais cette pratique est déconseillée dans la majorité des cas, car :
- L’ordre devient figé, et casse si on ajoute un champ au milieu ;
- Cela complexifie inutilement le code et les tests ;
- Cela déroute les technologies d’assistance, qui attendent un flux logique de haut en bas.
À privilégier : laissez le navigateur gérer le focus automatiquement, sauf cas très particuliers (modales, sliders, composants JavaScript dynamiques).
Si vous devez retirer temporairement un élément du cycle de tabulation (ex. : menu masqué), utilisez tabindex="-1"
avec prudence, et réactivez-le au bon moment.
Contrastes, couleurs et visibilité
Vous avez choisi une jolie palette pastel, un texte gris doux sur fond crème, une ambiance “légère”… sauf que pour une partie de vos visiteurs, c’est juste illisible. Que ce soit pour des personnes malvoyantes, daltoniennes, ou fatiguées, un bon contraste, c’est ce qui fait qu’on peut lire — ou pas.
Imaginons une zone d’alerte qui indique un changement de salle pour notre conférence :
<div class="alerte">
Attention : la salle a changé, rendez-vous en amphithéâtre B.
</div>
Et maintenant une version CSS problématique :
.alerte {
background-color: #fcecec;
color: #f99999;
padding: 1em;
}
Résultat : contraste très faible, message invisible pour certains utilisateurs.
Corrigeons :
.alerte {
background-color: #ff214f;
color: #ffffff;
padding: 1em;
font-weight: bold;
}
Pourquoi c’est utile ?
- Un contraste insuffisant rend un texte invisible pour beaucoup d’utilisateurs (dyslexie, basse vision, fatigue, lumière ambiante).
- Les navigateurs ne signalent pas ce problème automatiquement.
- Il est interdit (et contre-productif) de signaler une info uniquement par la couleur (ex : « champ en rouge = erreur »).
À tester à ce stade :
- WebAIM Contrast Checker : copiez vos couleurs et vérifiez qu’elles passent les niveaux AA ou AAA selon la taille du texte.
- WAVE : l’extension signale tous les problèmes de contraste insuffisant.
- Extensions navigateur : des outils comme Color Contrast Analyzer (TPGi) ou Accessibility Insights affichent les contrastes directement sur la page.

L’accessibilité visuelle, ce n’est pas que pour les malvoyants. C’est aussi pour ceux qui lisent dehors, sur smartphone, ou après une longue journée de travail. Bien voir, c’est déjà bien comprendre.
Dynamique et AJAX : garder le contrôle avec ARIA et JS propre
De plus en plus d’éléments de page s’affichent dynamiquement : validation instantanée, messages de confirmation, chargement de contenu sans rechargement complet. Ces effets sont utiles… mais souvent invisibles pour les lecteurs d’écran ou les utilisateurs clavier.
Reprenons notre formulaire de réservation. Lorsqu’il est envoyé avec succès via AJAX, on affiche un message sans recharger la page. Voici une mauvaise pratique fréquente :
fetch("traitement.php", { method: "POST", body: donnees })
.then(() => {
document.querySelector("#zone-message").innerText = "Votre réservation est enregistrée.";
});
Le message s’affiche… mais le lecteur d’écran ne le lit pas, car rien ne l’y pousse.
Voici une meilleure version, avec une zone ARIA dynamique :
HTML
<div id="zone-message" aria-live="polite" role="status"></div>
JavaScript
fetch("traitement.php", { method: "POST", body: donnees })
.then(() => {
const msg = document.getElementById("zone-message");
msg.innerText = "Votre réservation est enregistrée.";
msg.focus(); // si nécessaire, pour relecture immédiate
});
Pourquoi c’est utile ?
- L’attribut
aria-live="polite"
informe les lecteurs d’écran qu’un contenu va évoluer et doit être lu. role="status"
renforce ce comportement pour des messages non bloquants.- Cela fonctionne sans bloquer le fil d’exécution ni gêner les autres utilisateurs.
À tester à ce stade :
- Lecteur d’écran : testez si le message est bien lu sans interaction supplémentaire.
- Chrome DevTools → Accessibilité : l’onglet Computed Properties montre les rôles et les zones live.
- Plugin axe DevTools : permet de détecter les zones dynamiques non déclarées.

Comprendre aria-live
et role="status"
L’attribut aria-live
permet de signaler qu’une zone de la page va changer sans rechargement, et que ces changements doivent être annoncés automatiquement par les lecteurs d’écran. C’est essentiel pour rendre visibles des messages dynamiques comme les confirmations, erreurs, alertes…
Il peut prendre plusieurs valeurs :
off
(par défaut) : le contenu dynamique ne sera pas lu.polite
: le contenu sera lu dès que possible, sans interrompre ce qui est en cours.assertive
: le contenu sera lu immédiatement, en interrompant la lecture actuelle (à utiliser avec modération).
Dans notre exemple, aria-live="polite"
est suffisant pour une confirmation non urgente.
Le role="status"
est complémentaire : il renforce l’intention en indiquant que la zone est une notification d’état, attendue par l’utilisateur.
Ces rôles sont documentés sur la spécification ARIA du W3C : WAI-ARIA – Live Region Roles. En combinant aria-live
+ role
+ focus
, on rend un contenu vivant et perceptible dans un monde souvent silencieux pour les lecteurs d’écran.
Astuce : si vous créez une modale, une alerte ou un nouvel élément interactif, pensez à y déplacer le focus (.focus()
) dès son affichage. Un contenu visible n’est pas forcément actif ou accessible.
Rendre visibles et audibles les contenus médias
Images, vidéos, sons, illustrations, icônes… tous ces médias enrichissent l’expérience visuelle ou auditive. Mais pour certains utilisateurs, ils peuvent aussi représenter un mur d’incompréhension s’ils ne sont pas accompagnés des bons attributs, bons formats ou bons contrôles. L’accessibilité des contenus médias, ce n’est pas de l’esthétique : c’est de l’information rendue équitable.
Images : dire ce que l’on montre, ou taire ce qui ne compte pas
Chaque image devrait répondre à une question simple : « Apporte-t-elle un sens que le texte n’exprime pas déjà ? »
Cas 1 : Image informative
<img src="intervenant.jpg" alt="Marie Durand, designer web">
On précise ce que montre l’image. C’est lu par les lecteurs vocaux, et permet de comprendre l’image même sans la voir.
Cas 2 : Image décorative
<img src="ligne-separation.png" alt="" role="presentation">
On vide l’attribut alt
pour ignorer l’image. Le rôle presentation
supprime son exposition dans l’arbre d’accessibilité.
Cas 3 : Image cliquable
<a href="/programme.html">
<img src="bouton.png" alt="Voir le programme">
</a>
L’alternative textuelle joue ici le rôle du lien. Elle doit être explicite… Pour les schémas, infographies, ou images avec du texte embarqué, une description longue est à prévoir sous forme de paragraphe adjacent, ou via un lien « Description complète ».
Cas 4 : Schéma explicatif avec texte embarqué
<figure>
<img src="schema-ecosysteme.png" alt="Schéma de l’écosystème du projet" aria-describedby="desc-schema">
<figcaption>Écosystème des acteurs impliqués dans le projet</figcaption>
</figure>
<p id="desc-schema">
Description complète : Le schéma présente quatre cercles reliés. Au centre, “Pem’s Projects”, entouré de trois entités :
“Puce & Média” (recherche), “Epsyllum” (logistique), et “Clubs/associations” (usages). Des flèches bidirectionnelles relient ces pôles,
symbolisant l’interdépendance et la co-construction. Un cartouche précise que les données restent internes, sans diffusion externe.
</p>
Certains schémas ou infographies intègrent du texte dans l’image elle-même. Ce contenu, s’il n’est pas transcrit, devient invisible pour les utilisateurs de lecteurs d’écran. L’approche ci-dessus permet de le rendre accessible sans dénaturer la présentation :
- L’image reste visible pour tous, sans masquer l’info dans l’
alt
. - Le
aria-describedby
relie l’image à un bloc de texte lisible par les lecteurs vocaux. - Le texte est également présent visuellement, utile pour tous les utilisateurs.
- Si besoin, la phrase “Description complète” peut devenir un lien vers une page externe ou un PDF détaillé.
Vidéos : sous-titrer, décrire, contrôler
Une vidéo HTML5 sans sous-titre ni description, c’est une séquence muette… pour beaucoup. Voici une intégration correcte :
<video controls width="600" aria-describedby="video-desc">
<source src="presentation.mp4" type="video/mp4">
<track src="sous-titres.vtt" kind="subtitles" srclang="fr" label="Français" default>
Votre navigateur ne supporte pas la lecture vidéo.
</video>
<p id="video-desc">
Cette vidéo présente les intervenants de la conférence "Demain, le web".
</p>
À respecter :
- L’attribut
controls
rend la vidéo navigable au clavier. - Le
<track>
charge les sous-titres codés (format WebVTT). - Le texte adjacent décrit le contexte ou l’intention de la vidéo.
Pour une vidéo strictement visuelle (ex. : langage des signes, démonstration graphique), une audiodescription peut être ajoutée, soit en seconde piste audio, soit sous forme de transcription textuelle complète.
Sons, podcasts et lectures audio
Le son seul est un média puissant, mais à condition qu’il soit complété pour celles et ceux qui n’entendent pas ou ne peuvent pas activer l’audio.
- Toujours prévoir une transcription complète d’un fichier audio. Elle peut être en paragraphe, PDF, ou fichier
.txt
adjacent. - Ne jamais lancer un son automatiquement avec le son actif (
autoplay
sansmuted
), au risque de surprendre l’utilisateur. - Privilégier les lecteurs avec boutons visibles, accessibles via Tab, et bien étiquetés (
aria-label="Lecture"
, etc.).
Outils pour valider les médias
- WAVE : détecte l’absence d’
alt
, de contrôles, ou de contenu textuel alternatif. - Contrast Checker : utile pour vérifier la lisibilité des sous-titres ou légendes vidéo.
- MDN – WebVTT : guide complet pour créer des sous-titres.
Retenez ceci : si un contenu visuel ou sonore est important pour comprendre la page, il doit être rendu accessible — par une autre voie. Texte, transcription, lecture vocale ou interaction clavier : peu importe le canal, tant que l’information passe.
Conclusion
On ne code pas un site accessible pour “cocher une case”, ni même seulement pour respecter la loi. On le fait parce qu’un site, par définition, est une porte d’entrée. Si elle est trop étroite, trop haute, trop glissante… certains n’entreront jamais.
L’accessibilité, ce n’est pas un luxe. C’est un réflexe qu’on adopte dès la page blanche, qui améliore la qualité, la robustesse et la lisibilité de tout ce qu’on produit. Elle ne s’oppose ni au design, ni à la performance. Elle s’insère, discrète, mais essentielle.
Nous avons tenté ici de poser des bases. Mais l’accessibilité est vivante, évolutive, et surtout humaine. Pour continuer, nous vous invitons à explorer des exemples concrets, des témoignages d’usagers, et à tester vos propres créations autrement.