Esc
 Naviguer  Ouvrir Esc Fermer
Aller au contenu

5.3 — Accessibilité (a11y)

Débutant 25 min prérequis : axes 5.1 et 5.2 lus

🎯 Objectif : produire des sites utilisables par les 15 % de personnes ayant une situation de handicap (visuel, moteur, cognitif, auditif). Et accessoirement : tu y gagnes en SEO et en UX pour tout le monde.

À l'issue de cet axe, tu sauras :

  • Comprendre les 4 principes WCAG (POUR : Perceptible, Opérable, compréhensible, Robuste)
  • Atteindre la conformité WCAG 2.2 niveau AA
  • Tester avec axe-core, Lighthouse et un lecteur d'écran
  • Construire des composants courants (modal, menu, tabs) accessibles
  • Vérifier la navigation clavier complète

3 raisons (par ordre d’importance) :

  1. Éthique : ~15 % de la population est en situation de handicap. Les écarter = exclusion active.
  2. Légal : la directive européenne 2025 oblige les sites privés > certain CA à être accessibles. Amendes possibles.
  3. Business : meilleur SEO (Google récompense l’accessibilité), meilleure UX pour tous (mobile, situations dégradées, navigation clavier des power users).

WCAG 2.2 (Web Content Accessibility Guidelines) repose sur 4 principes : POUR.

PrincipeSens
PerceptibleLes utilisateurs perçoivent l’information (texte alt, sous-titres, contraste)
OpérableTout est utilisable au clavier, sans piège
UompréhensibleLisible, prévisible, aide à la saisie
RobusteCompatible avec assistive tech (lecteurs d’écran, zoom, etc.)

3 niveaux : A (minimum), AA (cible légale), AAA (rare en pratique).

Cible standard pour un projet web : AA.

<!-- Informative -->
<img src="/marie.jpg" alt="Marie souriant à l'école" />
<!-- Décorative -->
<img src="/decoration.svg" alt="" />
<!-- Pour le bouton avec icône -->
<button aria-label="Fermer la modale">
<svg aria-hidden="true">...</svg>
</button>

WCAG AA exige :

  • Texte normal (< 18pt) : ratio ≥ 4.5:1
  • Texte large (≥ 18pt ou 14pt gras) : ratio ≥ 3:1
  • Composants UI et éléments graphiques : ≥ 3:1
/* ❌ Insuffisant : 3.4:1 */
body { color: #888; background: #fff; }
/* ✅ AA : 4.5:1 */
body { color: #595959; background: #fff; }
/* ✅ AAA : 7:1 */
body { color: #333; background: #fff; }

Outils : Stark, Coolors contrast checker, DevTools Chrome (color picker affiche le ratio).

Tous les éléments interactifs doivent être atteignables et utilisables au clavier (Tab, Espace, Entrée, Flèches).

Test minute : appuie sur Tab depuis le début de ta page. Peux-tu tout atteindre ? L’ordre est-il logique ? Y a-t-il des pièges (focus qui ne peut plus sortir d’un élément) ?

/* Toujours visible le focus */
:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
/* JAMAIS ça */
*:focus { outline: none; } /* ❌ tu casses l'accessibilité */

Pour permettre aux utilisateurs clavier d’éviter de re-tabber dans la nav à chaque page :

<body>
<a href="#main" class="skip-link">Aller au contenu principal</a>
<header>...</header>
<main id="main">...</main>
</body>
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: black;
color: white;
padding: 0.5rem 1rem;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
<!-- ✅ Bon -->
<label for="email">E-mail</label>
<input id="email" type="email" required />
<!-- ✅ Aussi bon -->
<label>
E-mail
<input type="email" required />
</label>
<!-- ❌ Mauvais : placeholder ≠ label -->
<input type="email" placeholder="E-mail" />

Le placeholder disparaît dès que l’utilisateur tape. Toujours un label visible ; le placeholder peut servir d’indication complémentaire.

<label for="pwd">Mot de passe</label>
<input id="pwd" type="password" aria-describedby="pwd-error" aria-invalid="true" />
<p id="pwd-error" role="alert">Le mot de passe doit contenir au moins 8 caractères.</p>
  • aria-describedby lie l’input au message.
  • aria-invalid="true" annonce l’état d’erreur aux lecteurs d’écran.
  • role="alert" fait annoncer immédiatement le message dès qu’il apparaît.

7. Hiérarchie de titres logique (Compréhensible)

Section intitulée « 7. Hiérarchie de titres logique (Compréhensible) »

Un seul <h1>. Pas de saut. Le texte des titres reflète le contenu, pas le style. Voir 5.1.

<html lang="fr">

Permet aux lecteurs d’écran de prononcer correctement (un même mot ne se lit pas pareil en français et en anglais).

9. Touch targets ≥ 44×44 px (Opérable, WCAG 2.2)

Section intitulée « 9. Touch targets ≥ 44×44 px (Opérable, WCAG 2.2) »

Les boutons / liens cliquables doivent faire au moins 44 × 44 pixels (zone tap confortable au doigt).

button, .btn {
min-width: 44px;
min-height: 44px;
padding: 0.5rem 1rem;
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}

Pour les utilisateurs avec troubles vestibulaires, animations rapides = vertige.

Fenêtre de terminal
# Lighthouse intégré à Chrome — F12 puis onglet Lighthouse
# Auditer le panel Accessibility
# axe DevTools (extension Chrome/Firefox) — plus précis que Lighthouse
# CLI pour CI :
npx @axe-core/cli https://example.com
npx pa11y https://example.com
TestComment
Tab sur toute la pageOrdre logique ? rien d’oublié ?
Activer un bouton au clavierEspace et Entrée fonctionnent ?
Zoom 200 %Le contenu reste utilisable ?
Texte 200 % uniquement (Ctrl++)Pas de débordement ?
Lecteur d’écran (NVDA gratuit / VoiceOver Mac)Tu comprends la page sans la voir ?

Sur Mac : Cmd+F5 pour activer VoiceOver. Tab pour naviguer, Ctrl+Opt+→ pour explorer.

Sur Windows : NVDA (gratuit). Insert+down arrow pour lire en continu.

C’est inconfortable les premières fois, mais une heure passée à tester avec NVDA t’apprend plus que 10 articles.

<button id="open-modal" type="button">Ouvrir</button>
<dialog id="modal" aria-labelledby="modal-title">
<h2 id="modal-title">Confirmer la suppression</h2>
<p>Êtes-vous sûr ?</p>
<button autofocus>Annuler</button>
<button>Supprimer</button>
</dialog>
const modal = document.getElementById('modal');
document.getElementById('open-modal').addEventListener('click', () => {
modal.showModal(); // <dialog> natif gère focus trap, Esc, etc.
});

L’élément <dialog> natif (2022+) gère gratuitement :

  • Focus trap (le focus reste dans la modale).
  • Touche Escape pour fermer.
  • Backdrop (fond grisé).
  • Lecteurs d’écran : annonce le rôle de dialog.

Évite les libs JS si la balise native suffit.

Pour un vrai menu (pas juste un dropdown), regarde le pattern WAI-ARIA officiel — c’est subtil. En pratique, utilise une lib éprouvée (Radix UI, Headless UI) qui gère les claviers, focus, ARIA correctement.

Pareil — pattern complexe. Radix Tabs ou <details>/<summary> natifs si l’UX le permet (accordion plutôt que tabs).

<button aria-describedby="tip-info">
Info
</button>
<span id="tip-info" role="tooltip" hidden>Plus d'infos</span>

Mais les tooltips sont fragiles côté a11y (mobile, navigation clavier…). Utilise-les avec parcimonie ; préfère afficher l’info directement quand possible.

  • eslint-plugin-jsx-a11y : détecte des erreurs a11y dans les PR (React/JSX).
  • Pa11y CI ou @axe-core/playwright : tests E2E qui échouent si l’a11y baisse.
  • Lighthouse (intégré Chrome) — vue d’ensemble.
  • axe DevTools — plus précis que Lighthouse.
  • WAVE — bookmarklet.
  • HeadingsMap — visualise la hiérarchie des titres.
  • Stark (Figma, Chrome) — contraste, simulateur de daltonisme.
  • Color Oracle — simulateur daltonisme système-wide.
❌ ErreurPourquoi
outline: none sans alternativeCassé pour les utilisateurs clavier
<div onclick> au lieu de <button>Pas de focus, pas de Espace/Entrée, pas accessible
Texte uniquement sur imagePas indexable, pas zoomable, pas modifiable
Police < 14pxIllisible pour les seniors, malvoyants
Couleur seule pour transmettre l’infoDaltoniens (8 % des hommes) ne voient pas
Texte mince et clair sur fond clairContraste insuffisant
Animations qui bougent en permanenceVestibulaire + distraction
Boutons qui font moins de 24×24 pxTouch impossible sur mobile
Tu enlèves outline sur les boutons (`button:focus { outline: none; }`). Conséquence ?
Texte gris #888 sur fond blanc. Conforme WCAG AA ?
Tu as un bouton avec juste une icône X (fermer). Quel attribut ARIA ajouter ?
  • WCAG 2.2 — Quick Reference : w3.org/WAI/WCAG22/quickref
  • Web Accessibility Initiative — ARIA Authoring Practices : w3.org/WAI/ARIA/apg
  • A11y Project : a11yproject.com — checklists et patterns
  • Inclusive Components — Heydon Pickering (livre + site, gratuit)
  • Smashing Magazine — Accessibility : tag avec articles de référence

Fin de l’axe 5. Direction l’axe 6 — JavaScript & TypeScript, ou attaque l’exercice Refonte Lighthouse.