Aller au contenu

Accessibilité & robustesse du UI

Ce n'est pas une checklist

L'accessibilité n'est pas une étape qu'on ajoute à la fin. C'est une série de décisions techniques qu'on prend tout au long de l'intégration.

Ce qui distingue un intégrateur compétent d'un outil qui génère du code : le code généré par l'IA passe rarement les audits d'accessibilité sans correction. Il produit du HTML qui fonctionne visuellement, mais ignore systématiquement ce qui n'est pas visible à l'écran.

Grand résumé

  • Contraste et lisibilité
  • Focus visible et navigation clavier
  • Tailles de clic et états interactifs
  • Structure sémantique
  • Attributs d'accessiblité: Textes alternatifs, AREA, lien entre label et input
  • Auditer avec Lighthouse et axe DevTools

Contraste et lisibilité

Les deux seuils à retenir (WCAG AA)

Le WCAG (Web Content Accessibility Guidelines) définit des ratios de contraste minimaux entre la couleur du texte et son arrière-plan.

Type de contenu Ratio minimal
Texte normal (moins de 18px) 4.5 : 1
Grand texte (18px+ ou 14px gras) 3 : 1
Éléments d'interface (icônes, bordures de champs) 3 : 1
/* ❌ Problème fréquent : texte trop pâle sur fond clair */
.label {
  color: #aaaaaa; /* ratio ~2.3:1 sur blanc : insuffisant */
}

/* ✅ Correction */
.label {
  color: #767676; /* ratio ~4.5:1 sur blanc : seuil exact */
}


See the Pen DEMO Accessibilité - Contraste by TIM Montmorency (@tim-momo) on CodePen.


Vérifier le contraste directement dans DevTools

Chrome DevTools affiche le ratio de contraste directement dans le color picker :

  1. Inspecte un élément texte
  2. Clique sur la pastille de couleur dans le panneau CSS
  3. Le ratio s'affiche : un ✓ indique que le seuil AA est atteint, ✓✓ indique AAA

Capture d'écran du color picker de Chrome DevTools montrant le ratio de contraste et les icônes de validation

Petit exercice d'observation

  • 1. Ouvre le wiki du cours, la page courante dans Google Chrome: https://tim-montmorency.com/compendium/582-211-web2/css/accessibilite.html#petit-exercice-dobservation
  • 2. Si ce n'est pas le cas, mets le site en dark mode via cet icône en haut à droite: Bouton dark mode
  • 3. Inspecte ce texte jaune ⬅️
  • 4. Clique sur la pastille de couleur dans le panneau CSS
  • 5. Observe le ratio de contraste... Quel est-il? Est-ce que ça passe les normes de lisiblité et d'accessibilité selon WCAG ?
  • 6. Change maintenet le site en light mode via cet icône en haut à droite: Bouton light mode
  • 7. Inspecte ce texte jaune ⬅️
  • 8. Clique sur la pastille de couleur dans le panneau CSS
  • 9. Observe le ratio de contraste... Maintenant qu'est-il? Est-ce que ça passe les normes de lisiblité et d'accessibilité selon WCAG ?


Résumé constrate et lisibilité

See the Pen DEMO accessibilité: constrate by TIM Montmorency (@tim-momo) on CodePen.

Focus visible et navigation clavier

Pourquoi c'est important

Certains utilisateurs ne peuvent pas utiliser une souris : personnes avec des troubles moteurs, malvoyants qui utilisent un lecteur d'écran, utilisateurs avancés qui naviguent au clavier. Pour eux, le focus visible est le seul indicateur de leur position sur la page.


Le lien direct avec :focus-visible

Tu as vu :focus-visible dans la section précédente. C'est ici que son importance prend tout son sens :

/* ❌ Ce pattern est partout : et il brise l'accessibilité */
* {
  outline: none;
}

/* ✅ La bonne approche */
:focus {
  outline: none; /* retire l'outline au clic souris */
}

:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}


Ce que doit indiquer un état de focus

Un indicateur de focus accessible doit être :

  • Visible : contraste suffisant avec le fond (ratio 3:1 minimum)
  • Distinct : différent de l'état normal au repos
  • Stable : ne disparaît pas trop vite, n'est pas masqué par un overflow: hidden
/* Exemple d'un focus robuste */
.bouton:focus-visible {
  outline: 2px solid #2d6a4f;
  outline-offset: 3px;
  /* outline-offset sépare le contour de l'élément
     : évite qu'il se confonde avec la bordure */
}


See the Pen DEMO accessibilité: focus by TIM Montmorency (@tim-momo) on CodePen.


Tester soi-même

La méthode la plus rapide : pose ta souris et navigue avec Tab.

  • Tab : avancer vers l'élément focusable suivant
  • Shift+Tab : reculer
  • Enter ou Space : activer un bouton ou un lien

Si tu perds ta position à un moment, c'est un problème d'accessibilité.

Tailles de clic et états interactifs

La taille minimale recommandée

Le WCAG 2.5.5 recommande une zone cliquable d'au moins 44 × 44 pixels pour les éléments interactifs, particulièrement sur mobile et écran tactile.

/* ❌ Icône cliquable trop petite */
.btn-icone {
  width: 16px;
  height: 16px;
}

/* ✅ Zone de clic étendue sans changer l'apparence visuelle */
.btn-icone {
  width: 16px;
  height: 16px;
  padding: 14px; /* zone de clic : 44×44px: 16px+14px+14px=44px */
}

/* ✅ Ou avec min-width / min-height et centrer avec flexbox */
.btn-icone {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}


Les trois états interactifs obligatoires

Un élément cliquable doit avoir un style distinct pour chacun de ces états :

.bouton {
  background: #f5f4f0;
  border: 1px solid #e0ddd6;
  cursor: pointer;
}

/* 1. Survol souris */
.bouton:hover {
  background: #e8e6e0;
  border-color: #2d6a4f;
}

/* 2. Focus clavier */
.bouton:focus-visible {
  outline: 2px solid #2d6a4f;
  outline-offset: 3px;
}

/* 3. Clic / activation */
.bouton:active {
  transform: scale(0.97);
  background: #d8f3dc;
}


L'erreur la plus fréquente

Définir uniquement :hover et oublier :focus-visible et :active. Sur mobile, :hover n'existe pas : l'état :active est le seul feedback visuel disponible.


See the Pen DEMO accessibilité: états interactifs by TIM Montmorency (@tim-momo) on CodePen.

Structure HTML sémantique

Le HTML sémantique comme fondation

Un code accessible commence par un HTML qui utilise les bonnes balises pour les bons usages. Les lecteurs d'écran se fient à la sémantique pour annoncer le contenu aux utilisateurs.

<!-- ❌ Div soup : aucune information structurelle -->
<div class="header">
  <div class="nav">
    <div class="nav-item">Accueil</div>
    <div class="nav-item">À propos</div>
  </div>
</div>

<!-- ✅ Sémantique correcte -->
<header>
  <nav>
    <ul>
      <li><a href="/">Accueil</a></li>
      <li><a href="/a-propos">À propos</a></li>
    </ul>
  </nav>
</header>


Hiérarchie des titres

Les titres (h1 à h6) structurent la page comme une table des matières. Un lecteur d'écran peut naviguer directement d'un titre à l'autre.

<!-- ❌ Titres choisis pour leur taille, pas leur hiérarchie -->
<h1>Titre de page</h1>
<h3>Section importante</h3> <!-- on a sauté h2 -->
<h5>Sous-section</h5>       <!-- on a sauté h4 -->

<!-- ✅ Hiérarchie logique -->
<h1>Titre de page</h1>
<h2>Section importante</h2>
<h3>Sous-section</h3>

ℹ️ Si tu veux un h3 qui ressemble visuellement à un h2, change le style CSS : ne change pas la balise.


Attributs d'accessibilité

Textes alternatifs via l'attribut alt

Toute image qui porte une information doit avoir un attribut alt descriptif. Une image purement décorative doit avoir un alt vide pour être ignorée par les lecteurs d'écran.

<!-- ❌ Alt manquant : le lecteur d'écran lit le nom du fichier -->
<img src="graphique-ventes-q3.png">

<!-- ❌ Alt inutile : répète ce que l'entourage dit déjà -->
<img src="logo.png" alt="image du logo">

<!-- ✅ Alt informatif -->
<img src="graphique-ventes-q3.png" alt="Ventes Q3:hausse:23% par rapport à Q2">

<!-- ✅ Image décorative : ignorée par les lecteurs d'écran -->
<img src="separateur-decoratif.png" alt="">

Attributs ARIA essentiels

Quand le HTML sémantique ne suffit pas à décrire l'intention d'un élément, les attributs ARIA (Accessible Rich Internet Applications) prennent le relais. Ils transmettent aux technologies d'assistance des informations que le code visuel ne peut pas exprimer seul.

Les quatre attributs les plus courants en intégration :

aria-label

Donne un nom explicite à un élément interactif quand son contenu textuel est absent ou insuffisant (ex. : un bouton avec seulement une icône).

<!-- ❌ Le lecteur d'écran annonce "bouton" sans contexte -->
<button><img src="fermer.svg"></button>

<!-- ✅ Le lecteur d'écran annonce "Fermer le menu" -->
<button aria-label="Fermer le menu"><img src="fermer.svg" alt=""></button>

aria-hidden

Masque un élément aux technologies d'assistance. Utile pour les icônes décoratives ou les éléments visuels redondants.

<!-- L'icône est décorative : le lecteur d'écran l'ignore -->
<span aria-hidden="true"></span> Favori

aria-expanded

Indique si un élément dépliable (accordéon, menu) est ouvert ou fermé. Doit être mis à jour dynamiquement via JavaScript.

<button aria-expanded="false" aria-controls="menu-nav">
  Menu
</button>
<nav id="menu-nav" hidden>...</nav>

role

Redéfinit le rôle sémantique d'un élément quand la balise HTML ne reflète pas son usage réel.

<!-- Une div utilisée comme bouton : le clavier ne fonctionnera pas
     sans tabindex, mais le rôle aide les lecteurs d'écran -->
<div role="button" tabindex="0">Ajouter au panier</div>


Repères de navigation (landmarks)

Le document doit avoir une balise ARIA principale (main landmark).

Repères de navigation (landmarks)

Pour qu'un lecteur d'écran puisse sauter directement au contenu principal sans réécouter l'entête à chaque page, la page doit contenir une balise <main>. C'est ce qu'on appelle un landmark ARIA : un repère de navigation structurel.

Il est recommandé d'utiliser conjointement les balises HTML5 sémantiques et leurs équivalents ARIA, pour maximiser la compatibilité avec toutes les technologies d'assistance :

Balise HTML5 Équivalent ARIA
<header> role="banner"
<nav> role="navigation"
<main> role="main"
<footer> role="contentinfo"
<!-- ✅ Structure robuste : HTML5 + ARIA -->
<header role="banner">...</header>
<nav role="navigation">...</nav>
<main role="main">...</main>
<footer role="contentinfo">...</footer>

Tip

En pratique, les navigateurs modernes reconnaissent bien les balises HTML5 seules. Ajouter le role ARIA reste une bonne habitude pour garantir la compatibilité avec les lecteurs d'écran plus anciens.


Règle d'or ARIA

N'utilise pas ARIA pour corriger un mauvais choix de balise sémantique. Si tu peux utiliser <button>, <nav> ou <a>, fais-le : c'est toujours préférable.

Liens entre champs <input> et étiquettes <label>

Tout champ de formulaire doit être explicitement lié à son étiquette via l'attribut for (sur le <label>) et id (sur le champ). Sans ce lien, le lecteur d'écran ne sait pas à quoi correspond le champ.

<!-- ❌ Label et champ non liés : le lecteur d'écran les annonce séparément -->
<label>Courriel</label>
<input type="email">

<!-- ✅ Lien explicite : cliquer sur le label active le champ -->
<label for="courriel">Courriel</label>
<input type="email" id="courriel">

Langue du document et texte des liens

  • Langue de la page : permet au lecteur d'écran de prononcer correctement le contenu. Simple et souvent oublié.
  • Liens explicites : Un lien qui dit "cliquez ici" ou "en savoir plus" est inutilisable hors contexte. Le texte du lien doit décrire la destination.

Auditer avec Lighthouse et axe DevTools

Deux outils, deux usages

Lighthouse (intégré à Chrome DevTools) donne un score global et une liste de problèmes avec leur impact. Idéal pour un audit rapide et une vue d'ensemble.

axe DevTools (extension Chrome) est plus précis sur les violations spécifiques du WCAG. Il indique exactement quel critère est violé et pourquoi.


Comment lancer un audit Lighthouse

  1. Ouvre DevTools (F12 ou Cmd+Option+I)
  2. Onglet Lighthouse
  3. Coche Accessibility (décoche les autres pour aller plus vite)
  4. Clique Analyze page load
  5. Lis le rapport : chaque problème est expliqué avec sa cause et son impact


Ce que Lighthouse ne détecte pas

Lighthouse automatise environ 30 à 40% des vérifications d'accessibilité. Le reste requiert une vérification manuelle. Un score de 100 ne garantit pas une page accessible.

Ce qu'il ne peut pas détecter automatiquement :

  • Si les textes alternatifs sont pertinents (il détecte leur absence, pas leur qualité)
  • Si la navigation clavier est logique (ordre du focus)
  • Si le contenu est compréhensible pour quelqu'un qui ne voit pas la page

Cette semaine (semaine 4), avant la remise

Tu auras à faire un audit d'accessibilité avec Lighthouse sur ton propre projet Solarix. L'objectif n'est pas d'atteindre 100 : c'est de comprendre chaque problème signalé et de pouvoir expliquer comment tu le corrigerais (ou comment tu l'as corrigé).


Démo en classe

La démo suivante présente une page avec des erreurs d'accessibilité intentionnelles. On va l'auditer ensemble avec Lighthouse et axe DevTools pour voir exactement ce que les outils détectent : et ce qu'ils manquent.

Voir la page de démo →

Résumé : Ce qu'un intégrateur doit toujours vérifier

Quoi vérifier Comment
Contraste texte / fond DevTools color picker, ou WebAIM Contrast Checker
Focus clavier visible Naviguer à la ++Tab ↹++ et observer
Zones cliquables ≥ 44px Inspecter les dimensions dans DevTools
États hover, focus, active Tester manuellement chaque état
Hiérarchie des titres Onglet Accessibility dans DevTools
Textes alternatifs pertinents Lire chaque alt à voix haute : est-ce utile?
Attributs ARIA présents et pertinents Lire chaque attribut : est-ce qu'il compense un vrai manque sémantique?
Audit global Lighthouse > Accessibility