Cours HTML et CSS · Module 10: Accessibilité (a11y)
La navigation au clavier
Dans cette leçon8
Pose ta souris un instant et essaie d'acheter un billet pour le musée uniquement avec la touche Tab. Si, après quelques pressions, tu ne sais plus où tu te trouves, ou si le bouton « Acheter » ne réagit pas du tout, tu viens de ressentir à quoi ressemble Internet pour beaucoup de gens. Dans l'Égypte antique, les routes et les couloirs des temples étaient planifiés avec précision afin que chaque pèlerin puisse atteindre sa destination. De la même manière, les sites web doivent offrir des chemins de navigation clairs aux utilisateurs qui n'utilisent pas la souris - ils naviguent exclusivement au clavier.
Pourquoi la navigation au clavier est-elle importante ?
De nombreuses personnes utilisent les sites web uniquement au clavier :
- Les personnes à mobilité réduite
- Les utilisateurs de lecteurs d'écran
- Les utilisateurs avancés (programmeurs, power users)
- Les personnes ayant une blessure temporaire (par exemple, un bras cassé)
De plus, de nombreuses technologies d'assistance, comme la commande vocale ou les contacteurs, fonctionnent en simulant des pressions de touches. Une page qui se manie bien au clavier fonctionne donc aussi avec elles.
Les touches de navigation de base
| Touche | Fonction |
|---|---|
Tab | Passer à l'élément interactif suivant |
Shift + Tab | Revenir à l'élément précédent |
Entrée | Activer un lien ou un bouton |
Espace | Activer un bouton, cocher une case |
Touches fléchées | Naviguer dans les menus, les boutons radio, les tablist |
Échap | Fermer une boîte de dialogue, annuler |
Tab parcourt les éléments dans l'ordre où ils figurent dans le code HTML, et non dans l'ordre où tu les vois à l'écran. C'est pourquoi, sur une page typique, le focus se pose successivement sur le lien d'évitement, sur les liens de la navigation, sur les éléments interactifs du contenu principal et, pour finir, sur les liens du pied de page.
Le focus et tabindex
Le focus naturel
Le focus, c'est comme une torche dans un couloir sombre - il montre devant quel élément tu te tiens en ce moment. Certains éléments HTML sont naturellement focusables, ce qui veut dire que tu peux les atteindre avec Tab sans aucun attribut :
1<!-- Ces éléments sont naturellement focusables -->
2<a href="/link">Lien</a>
3<button>Bouton</button>
4<input type="text">
5<select>...</select>
6<textarea>...</textarea>
7
8<!-- Ces éléments ne sont PAS naturellement focusables -->
9<div>Impossible de l'atteindre avec Tab</div>
10<span>Celui-ci non plus</span>
11<p>Et pas celui-ci</p>Les liens dotés d'un attribut href et les boutons réagissent aussi aux touches d'emblée : un lien à Entrée, un bouton à Entrée et à Espace. Le simple texte d'un <div>, d'un <span> ou d'un <p> n'est pas interactif, alors Tab le saute - et c'est très bien ainsi, car personne ne veut s'arrêter sur chaque paragraphe.
L'attribut tabindex
L'attribut tabindex contrôle si et quand un élément reçoit le focus. Il accepte trois sortes de valeurs - deux utiles et une qu'il faut éviter :
1<!-- tabindex="0" - l'élément devient focusable dans l'ordre naturel -->
2<div tabindex="0" role="button" onclick="handleClick()">
3 Clique ici
4</div>
5
6<!-- tabindex="-1" - focusable par programmation, mais PAS via Tab -->
7<div tabindex="-1" id="error-message">
8 Une erreur s'est produite !
9</div>
10
11<!-- tabindex="1+" - À ÉVITER ! Modifie l'ordre naturel -->
12<!-- C'est un antipattern qui provoque le chaos dans la navigation -->
13<input tabindex="3" placeholder="Troisième">
14<input tabindex="1" placeholder="Premier">
15<input tabindex="2" placeholder="Deuxième">tabindex="0" insère un élément dans l'ordre de tabulation selon sa place dans le code. tabindex="-1" ne l'ajoute pas à l'ordre de Tab, mais permet à un script d'y déplacer le focus, par exemple vers un message d'erreur. Les valeurs positives font passer des éléments avant le reste de la page, si bien que l'ordre ne correspond plus à ce que l'on voit.
Règle : N'utilise que tabindex="0" et tabindex="-1". N'utilise jamais de valeurs positives !
Remarque aussi qu'un <div> avec role="button" reçoit bien le focus, mais ne réagit toujours ni à Entrée ni à Espace - la gestion des touches doit être écrite en JavaScript. C'est pourquoi je te recommande un <button> natif, qui fait tout cela gratuitement.
Les liens d'évitement (skip links)
Imagine un pèlerin qui, chaque fois qu'il entre dans le temple, doit longer les mêmes colonnes avant d'atteindre le sanctuaire. Les liens d'évitement permettent aux utilisateurs du clavier de sauter la navigation répétitive et d'aller directement au contenu principal :
1<!-- Lien d'évitement - premier élément de la page -->
2<a href="#main-content" class="skip-link">
3 Aller au contenu principal
4</a>
5
6<header>
7 <nav>
8 <!-- Longue navigation que l'utilisateur peut sauter -->
9 <a href="/">Accueil</a>
10 <a href="/exhibitions">Expositions</a>
11 <a href="/tickets">Billets</a>
12 <a href="/contact">Contact</a>
13 </nav>
14</header>
15
16<main id="main-content">
17 <h1>Bienvenue au musée égyptien</h1>
18 <!-- ... -->
19</main>Le lien fonctionne grâce à une ancre : href="#main-content" pointe vers l'élément qui porte id="main-content". La navigation elle-même ne change pas - le lien d'évitement permet seulement de la contourner. Il faut maintenant le cacher aux utilisateurs de la souris et l'afficher dès qu'il reçoit le focus :
1/* Lien d'évitement masqué visuellement, mais visible au focus */
2.skip-link {
3 position: absolute;
4 top: -40px;
5 left: 0;
6 background: #000;
7 color: #fff;
8 padding: 8px 16px;
9 z-index: 100;
10 transition: top 0.3s;
11}
12
13.skip-link:focus {
14 top: 0;
15}Le lien attend au-dessus du bord de la page, et :focus le ramène à sa place dès la première pression sur Tab. La valeur exacte (-40px ou -50px) n'a pas d'importance, du moment que le lien se cache entièrement. N'utilise pas display: none, car un élément masqué de cette façon ne peut pas recevoir le focus.
Le focus visible
Le contour (outline) est le seul signal qui indique où brûle la torche. Ne supprime jamais l'outline des éléments focusables - compare ces deux approches :
1/* MAUVAIS - masquer le focus */
2*:focus {
3 outline: none; /* NE FAIS PAS ÇA ! */
4}
5
6/* BON - focus personnalisé mais visible */
7a:focus-visible,
8button:focus-visible {
9 outline: 3px solid #d4af37;
10 outline-offset: 2px;
11 border-radius: 2px;
12}La pseudo-classe :focus-visible est préférable à :focus, car elle affiche le contour pendant la navigation au clavier, mais pas quand tu cliques sur un bouton avec la souris (les champs de texte l'affichent toujours, parce qu'il faut savoir où l'on écrit). La bonne version ne cache rien - elle change seulement la couleur du contour et l'écarte de 2px.
Le piège de focus (focus trap) dans les boîtes de dialogue
Lorsque tu ouvres une modale, le focus doit être « piégé » à l'intérieur - sinon, l'utilisateur du clavier errera dans la page cachée sous la fenêtre. Le HTML propose un élément tout prêt pour cela :
1<dialog id="ticket-dialog" aria-labelledby="dialog-title">
2 <h2 id="dialog-title">Acheter un billet</h2>
3 <form>
4 <label for="quantity">Nombre de billets :</label>
5 <input type="number" id="quantity" min="1" max="10" value="1">
6 <button type="submit">Acheter</button>
7 <button type="button" onclick="closeDialog()">Annuler</button>
8 </form>
9</dialog>Un élément <dialog> ouvert avec la méthode showModal() gère le focus automatiquement : il le déplace dans la fenêtre et rend le reste de la page inerte, si bien que Tab ne peut pas s'échapper derrière la fenêtre. La touche Échap ferme une telle boîte de dialogue, et le focus revient à l'élément qui était actif avant son ouverture.
La navigation accessible
Pour finir, voici une navigation avec des rôles ARIA supplémentaires. Observe bien les attributs role et aria-current :
1<nav aria-label="Navigation principale">
2 <ul role="menubar">
3 <li role="none">
4 <a href="/" role="menuitem">Accueil</a>
5 </li>
6 <li role="none">
7 <a href="/exhibitions" role="menuitem"
8 aria-current="page">Expositions</a>
9 </li>
10 <li role="none">
11 <a href="/tickets" role="menuitem">Billets</a>
12 </li>
13 </ul>
14</nav>L'attribut aria-current="page" indique au lecteur d'écran sur quelle page l'utilisateur se trouve actuellement. Attention toutefois : les rôles menubar et menuitem annoncent un menu d'application piloté avec les touches fléchées, que tu devrais programmer toi-même. Pour la navigation ordinaire d'un site, un <nav> contenant une liste de liens suffit - et c'est ce que je te recommande.
La navigation au clavier est comme des couloirs clairement balisés dans une pyramide - sans eux, même la chambre la plus magnifiquement décorée reste inaccessible à de nombreux visiteurs. Dans la prochaine leçon, tu mettras ces connaissances en pratique dans les formulaires, où Tab te conduit de champ en champ.
Pratique
Pose la souris et parcours la page de l'éditeur ci-dessous uniquement avec Tab. Vérifie que le lien d'évitement apparaît en premier et que tu vois toujours où se trouve le focus :
Code de cette leçon : index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Navigation au clavier</title>
7 <link rel="stylesheet" href="style.css">
8</head>
9<body>
10 <!-- Lien d'évitement -->
11 <a href="#main-content" class="skip-link">
12 Aller au contenu principal
13 </a>
14
15 <header>
16 <h1>Musée égyptien</h1>
17 <nav aria-label="Navigation principale">
18 <ul>
19 <li><a href="#exhibitions" aria-current="page">Expositions</a></li>
20 <li><a href="#tickets">Billets</a></li>
21 <li><a href="#contact">Contact</a></li>
22 </ul>
23 </nav>
24 </header>
25
26 <main id="main-content">
27 <h2>Teste la navigation au clavier</h2>
28 <p>Utilise la touche <kbd>Tab</kbd> pour passer d'un élément à l'autre.
29 Essaie <kbd>Shift+Tab</kbd> pour revenir en arrière.</p>
30
31 <section id="exhibitions">
32 <h3>Éléments interactifs</h3>
33
34 <a href="#link1">Lien vers exposition 1</a>
35 <a href="#link2">Lien vers exposition 2</a>
36
37 <button onclick="alert('Cliqué !')">
38 Clique-moi (Entrée ou Espace)
39 </button>
40
41 <div class="custom-btn" tabindex="0" role="button"
42 onclick="alert('Div-bouton !')"
43 onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();alert('Div-bouton !')}">
44 Div avec tabindex="0" (focusable lui aussi)
45 </div>
46 </section>
47
48 <section id="tickets">
49 <h3>Formulaire avec navigation au clavier</h3>
50 <form>
51 <label for="fname">Prénom :</label>
52 <input type="text" id="fname" name="fname">
53
54 <label for="lname">Nom :</label>
55 <input type="text" id="lname" name="lname">
56
57 <label for="ticket-type">Type de billet :</label>
58 <select id="ticket-type" name="ticket">
59 <option value="normal">Normal</option>
60 <option value="reduced">Réduit</option>
61 <option value="family">Famille</option>
62 </select>
63
64 <button type="submit">Acheter un billet</button>
65 </form>
66 </section>
67 </main>
68
69 <footer>
70 <p>Essaie d'arriver jusqu'ici avec Tab - combien de fois dois-tu appuyer dessus ?</p>
71 <p>Maintenant, remonte en haut et utilise le lien d'évitement !</p>
72 </footer>
73</body>
74</html>Souviens-toi : Tab est un pèlerin qui parcourt les couloirs de ta pyramide - le lien d'évitement raccourcit son chemin, et le focus visible est la torche qui montre où il se tient.
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Quelles valeurs de l'attribut tabindex sont recommandées à l'usage ?
Tâches pratiques dans le jeu
- Clique dans l'ordre
Compose un lien d'évitement correct en HTML :
- Éditeur de code
Ajoute un lien d'évitement au début de la page, id="main-content" à main, et des styles CSS pour .skip-link (masqué, visible au focus). Ajoute aussi focus-visible pour a, button et input.
- Tri vertical
Range l'ordre typique de navigation au Tab sur une page web :