La pagination
Une pagination est une liste de liens dans une zone de navigation nommée. Tout se joue sur ce que « 3 » annonce quand on le sort de la page. Démo, code, critères RGAA.
5 critères RGAA en jeu
Essayez-la
Résultats 37 à 48 sur 78
Tabulez dans la pagination : chaque lien est un arrêt, et rien d’autre n’est à apprendre — c’est un composant sans clavier propre. Puis actionnez le bouton d’inspection : il lit le DOM réel et affiche le nom accessible de chaque lien, tel qu’un lecteur d’écran le donne dans sa liste de liens — chevrons décoratifs exclus, comme il les exclut. Enfin, depuis la deuxième page, activez « Page précédente » à la touche Entrée : le lien s’efface, et le focus se repose sur le lien de la page devenue courante plutôt que de tomber dans le vide.
Cette démo existe aussi en page autonome.
L’erreur courante
Une rangée de chiffres, la page courante peinte en bleu, deux chevrons aux extrémités.
<!-- À ne pas faire -->
<div class="pagination">
<a href="?page=3" class="fleche">‹</a>
<a href="?page=1">1</a>
<a href="?page=2">2</a>
<span class="actif">3</span>
<a href="?page=4">4</a>
<a href="?page=5">5</a>
<a href="?page=5" class="fleche">›</a>
</div> /* À ne pas faire : l'état ne tient qu'à un fond coloré */
.actif {
background: #1d4ed8;
color: #fff;
} Passez cette pagination dans la liste de liens d’un lecteur d’écran, et voici ce qu’il en reste : « ‹ », « 1 », « 2 », « 4 », « 5 », « › ». Six liens, aucune destination.
On croit souvent qu’un aria-label="Pagination" sur le conteneur sauve les
intitulés numérotés. Il ne les sauve pas. Le contexte du
lien que le RGAA accepte est limitatif : la phrase,
le paragraphe, l’item de liste, le titre qui précède, la cellule d’en-tête ou de
données. Le nom d’une région n’y est pas. Un lien dont l’intitulé est « 3 »
reste non explicite, quel que soit le nom du <nav> qui l’entoure.
Trois variantes secondaires, dans la même page :
- Le chevron nu.
<a href="?page=4">›</a>n’a pour intitulé qu’un caractère typographique ; en SVG sans alternative, il n’en a aucun, et le lecteur d’écran lit l’URL. On entend alors « point d’interrogation page égale quatre ». - La page courante en
<span>. Elle sort de la liste de liens, et le lecteur d’écran passe de « 2 » à « 4 » sans rien annoncer entre les deux : le rang courant devient introuvable au clavier comme à la voix. - Le lien « précédent » grisé sur la première page. Grisé n’est pas désactivé : il garde le focus, s’active, et mène à une page qui n’existe pas.
Le code, pas à pas
1. Une zone de navigation, nommée
<nav aria-label="Pagination des résultats">
…
</nav> Le <nav> n’est pas décoratif : le critère 9.2 demande que les zones de
navigation principales et secondaires soient structurées ainsi, et une
pagination en est une. Le glossaire du référentiel le dit d’ailleurs en toutes
lettres, en rangeant « une liste de navigation d’une liste de résultats » parmi
les barres de navigation.
L’aria-label distingue ce <nav> des autres. Une page en porte souvent trois
— navigation principale, fil d’Ariane, pagination — et sans nom, la liste des
régions d’un lecteur d’écran affiche trois fois « navigation ». Le référentiel
n’impose pas ce nom ; l’utilisabilité, oui.
Une réserve : ne nommez pas la région « Navigation de pagination ». Le rôle est déjà annoncé, et l’on entendrait « navigation de pagination, navigation ».
2. Une liste, parce que c’en est une
<nav aria-label="Pagination des résultats">
<ol>
<li><a href="?page=1">Page 1</a></li>
<li><a href="?page=2">Page 2</a></li>
</ol>
</nav> Des numéros alignés sont « des informations regroupées visuellement sous forme
de liste » au sens du critère 9.3 : le balisage de liste est attendu. L’<ol> plutôt que l’<ul>, puisque l’ordre porte du sens.
Le gain est concret : le lecteur d’écran annonce « liste de 7 éléments » et le rang de chacun. C’est ce qui remplace le repère visuel « je suis au milieu ».
Comme les puces sont retirées en CSS, ajoutez role="list" sur l’<ol>. Ce
n’est pas une exigence du référentiel — un <ol> sans puces reste correctement
balisé au sens du 9.3 — mais certaines versions de Safari avec VoiceOver
retirent le rôle de liste quand list-style: none est appliqué, et le rôle
explicite le rend.
3. Des intitulés qui se suffisent
<a href="?page=3"><span class="sr-only">Page </span>3</a> Le nom accessible devient « Page 3 », l’affichage reste « 3 ». C’est le compromis habituel : le critère 6.1 est satisfait, la pagination garde sa largeur.
Un aria-label="Page 3" sur un lien qui affiche « 3 » fonctionne aussi, et
respecte le test 6.1.5 — le nom accessible contient au moins l’intitulé
visible. Le complément masqué lui reste préférable pour une raison qui n’est
pas dans le référentiel : un utilisateur de commande vocale dit « cliquer sur
Page 3 » et le navigateur trouve le texte, là où un aria-label seul crée
parfois un décalage entre ce qui se voit et ce qui se prononce.
4. Les flèches portent un nom, le chevron est décoratif
<a href="?page=3">
<span aria-hidden="true">‹</span> Page précédente
</a> Le texte fait l’intitulé, le chevron ne fait que l’illustrer — d’où
l’aria-hidden, qui évite qu’un lecteur d’écran ne prononce le caractère. Si
la place manque et que la flèche doit rester seule, l’alternative est un aria-label="Page précédente" : ce qui n’est jamais acceptable, c’est un lien
sans aucun intitulé, ce que le critère 6.2 relève directement.
« Précédente » et « suivante », plutôt que « Page 3 » et « Page 5 » : le lien dit ce qu’il fait, et son intitulé ne change pas d’une page à l’autre.
Sur la première page, retirez le lien « précédente » du DOM plutôt que de le
griser. Un <a> n’a pas d’état désactivé : aria-disabled="true" l’annonce
sans l’empêcher, et le clic partirait quand même.
5. La page courante : aria-current, et un signe visible
<li>
<a href="?page=4" aria-current="page"><span class="sr-only">Page </span>4</a>
</li> aria-current="page" est l’annonce : « Page 4, lien, page actuelle ». Le lien
reste un lien — il permet de recharger, et surtout il reste dans la liste de
liens, à sa place dans la suite des numéros.
Côté visible, le critère 3.1 tranche : l’information ne doit pas être portée par la seule couleur, et un fond bleu est exactement cela. Doublez-le d’une graisse, d’un trait épais, d’un encadrement — d’une forme, en somme. La démo emploie une graisse et une bordure basse de trois pixels.
Le référentiel nomme aria-current. Le glossaire « Information (donnée par la
couleur) », rattaché au critère
3.1, range « aria-current » parmi les compléments au niveau du code qui
accompagnent un moyen graphique ou un autre style typographique : « Un autre
style typographique (gras, italique, taille de texte, autre police, etc) et par
le biais d’un complément au niveau du code (aria-label, title, texte masqué,
aria-current, etc.) ». Les deux vont ensemble : la graisse et le trait pour
l’œil, aria-current="page" pour les technologies d’assistance.
6. Si la liste est longue : tronquer sans mentir
Au-delà d’une dizaine de pages, on n’affiche plus tout : 1 … 4 5 6 … 42.
Les points de suspension ne sont pas un lien et ne doivent pas en devenir un.
Mettez-les dans un <li> avec aria-hidden="true", ou remplacez-les par un
saut explicite — un lien « Page 20 » vaut mieux qu’un « … » qu’on ne peut pas
viser.
7. Une pagination qui ne recharge pas doit s’annoncer
Quand la navigation recharge la page, le changement se dit tout seul : nouveau titre de document, focus replacé en tête. Quand la liste se met à jour en place, rien ne bouge pour un lecteur d’écran — le focus reste sur le lien, et la liste a changé derrière.
Deux réponses, à combiner : une région role="status" présente dès le premier
rendu qui annonce « Résultats 37 à 48 sur 78 », et le focus déplacé en tête de
la liste de résultats. La région créée au moment de l’annonce n’est pas
restituée.
Le focus n’est pas seulement à déplacer, il est à rattraper : le lien qu’on
vient d’activer peut disparaître du DOM, puisque « précédente » n’existe plus
une fois la première page atteinte. Le focus retombe alors sur body, sans
rien annoncer. À défaut d’une liste de résultats où le poser — c’est le cas de
la démo ci-dessus —, replacez-le sur le lien de la page devenue courante, qui
survit à tous les rendus.
8. En avez-vous besoin ?
Une pagination sert à retrouver sa place et à revenir. Si vos contenus se lisent d’un flux continu, un bouton « Afficher 12 résultats de plus » est plus simple et plus sûr au clavier. Si l’on doit pouvoir citer, partager, revenir en arrière ou imprimer un rang précis, la pagination avec ses URL reste supérieure — c’est son vrai avantage sur le défilement infini, qui n’en a aucun de ce côté.
Au clavier
Une pagination n’a pas de clavier propre : ce sont des liens, et le navigateur
fait tout. Il n’y a ni flèches à câbler, ni tabindex à poser. Si vous vous
surprenez à écrire un keydown, c’est que le composant a dérivé.
| Touche | Effet |
|---|---|
| Tab | Passe au lien suivant de la pagination, dans l’ordre affiché. |
| Entrée | Suit le lien. Avec rechargement, le focus repart en tête de page ; sans rechargement, c’est à vous de le replacer — la démo le pose sur le lien de la page devenue courante. |
| Navigation par régions | Amène directement à la pagination, parce qu’elle est un <nav> nommé. |
| Liste des liens | Affiche les intitulés hors contexte — le seul test qui compte ici. |
Ce que le lecteur d’écran restitue
En entrant dans la région : « Pagination des résultats, navigation, liste de 7 éléments ». Sur un lien : « Page 3, lien, 3 sur 7 ». Sur la page en cours : « Page 4, lien, page actuelle ». La formulation varie d’un lecteur à l’autre, les informations non — nom de la région, nature de liste, rang, intitulé explicite, état courant.
Le diagnostic inverse se lit vite. Si vous n’entendez que des chiffres, les
compléments masqués manquent. Si vous n’entendez pas « 3 sur 7 », il n’y a pas
de liste — des <span> alignés, ou une <ol> privée de son rôle par list-style: none. Si vous n’entendez jamais « page actuelle », aria-current manque, ou la page en cours n’est pas un lien. Si vous entendez une URL, c’est
un chevron sans intitulé.
Checklist
- Un
<nav>avec unaria-labelqui ne répète pas le mot « navigation ». - Une
<ol>, avecrole="list"si les puces sont retirées en CSS. - Chaque numéro complété : nom accessible « Page 3 », pas « 3 ».
- Les flèches nommées « Page précédente » et « suivante », chevron
aria-hidden. - Le lien indisponible retiré du DOM, jamais grisé.
aria-current="page"sur la page en cours, et un signe visible non coloré.- Sans rechargement de page, une région
role="status"présente dès le départ, et le focus replacé après le changement de page.
Les critères RGAA en jeu
- Critère 6.1 — Liens explicites
Sortis de la page, des liens « 1 », « 2 », « 3 » ne disent plus rien — et le nom de la zone de navigation ne figure pas parmi les six contextes que le référentiel accepte pour compléter un intitulé.
- Critère 6.2 — Intitulé de lien
Les flèches précédent et suivant sont souvent un chevron sans texte : le lien n'a alors aucun intitulé, et le lecteur d'écran se rabat sur son URL.
- Critère 3.1 — Information donnée par la couleur
La page courante n'est signalée que par un fond coloré dans la plupart des paginations : l'information disparaît pour qui ne distingue pas cette couleur.
- Critère 9.2 — Cohérence de la structure du document
Une pagination est une zone de navigation secondaire, et attend donc une balise nav — que les paginations bricolées en div ne portent pas.
- Critère 9.3 — Structure des listes
Les numéros de page forment visuellement une liste : les enchaîner en span prive le lecteur d'écran du nombre de pages et du rang de chacune.
Vérifiez votre composant avec l'extension
Pour aller plus loin
- Les liens : la fiche mère de celle-ci — ce qu’un intitulé doit contenir, et pourquoi la liste de liens est le bon banc d’essai.
- Critère 6.1 — Liens explicites et « Contexte du lien » au glossaire : la liste limitative des six contextes qui peuvent compléter un intitulé.
- Critère 12.2 — Place constante du menu : une pagination est une barre de navigation, et doit donc rester au même endroit d’une page à l’autre de l’ensemble.
- Les listes : pourquoi
role="list"accompagne toute liste dont les puces sont retirées.
Sources
- ARIA APG — Link Pattern — ce qu’un lien doit offrir, et pourquoi un
<a href>suffit - MDN —
aria-current— les valeurs de l’attribut, dontpage - WCAG — Understanding 2.4.4 Link Purpose (In Context) — le pourquoi normatif de l’intitulé explicite
- GOV.UK Design System — Pagination — quand paginer, et quand préférer « afficher plus »