Le lecteur média
Le lecteur natif du navigateur donne le clavier, les noms et les états sans une ligne de script ; un lecteur maison les reprend tous à zéro. Ce qu'il faut alors rendre : lecture, son, sous-titres et position — atteignables au clavier, nommés, l'état annoncé.
4 critères RGAA en jeu
Essayez-le
Extrait simulé — aucune vidéo n'est chargée, seule la barre de contrôle est réelle.
Un audit commence par le choix de l'échantillon.
0:00 / 0:30
Le contrôle qui a le focus
Tabulez jusqu'au lecteur : chaque arrêt s'affiche ici, avec le nom, le rôle et l'état lus dans le DOM.
Lâchez la souris et tabulez : le focus s’arrête sur les cinq contrôles, et le panneau du dessous affiche, pour chacun, le nom, le rôle et l’état qu’il lit dans le DOM — et quand aucun attribut ne porte l’état, il le dit plutôt que de le deviner. Sur la barre de progression, les flèches déplacent la lecture d’une seconde et
Début ramène au commencement. Activez le bouton de lecture sans bouger le focus : son nom passe de « Lecture » à « Pause », et c'est là tout l'état.Cette démo existe aussi en page autonome.
L’erreur courante
Le lecteur maison, c’est une image de fond, deux div cliquables et une barre
qu’on traîne à la souris.
<!-- À ne pas faire -->
<div class="lecteur">
<div class="bouton" onclick="basculer()">▶</div>
<div class="barre" onmousedown="deplacer(event)">
<div class="remplissage" style="width: 37%"></div>
</div>
</div> Le div cliquable ne prend pas le focus et ne répond ni à Entrée ni
à Espace : la vidéo ne se lance pas au clavier. Son nom, s’il en
avait un, serait le caractère « ▶ » — que les lecteurs d’écran restituent
diversement, quand ils le restituent.
La barre est pire, parce qu’elle est irremplaçable. Rien d’autre dans la page
ne permet de se déplacer dans le média : onmousedown exclut d’un coup le
clavier, et personne ne peut revenir sur une phrase manquée. C’est le contrôle
que les lecteurs maison ratent le plus souvent, et celui dont l’absence coûte
le plus cher.
Trois variantes, aussi répandues :
- La barre de contrôle qui apparaît au survol (
.lecteur:hover .commandes). Au clavier, on tabule dans des boutons invisibles — ou, si elle est masquée pour de bon, on ne les atteint jamais. Il faut au minimum ajouter:focus-within. - La barre qui s’efface après trois secondes d’inactivité. Si le bouton qui avait le focus disparaît du document, le focus repart au début de la page : c’est exactement ce que le test 7.3.2 interdit à un script.
- Le bouton dont l’icône change mais pas le nom :
aria-label="Lecture"reste en place pendant que le pictogramme passe à la pause. Le nom ment sur l’état, et personne ne sait plus si le média joue.
Le code, pas à pas
1. <video controls> fait déjà tout cela
<video controls width="640">
<source src="audit.mp4" type="video/mp4" />
<track kind="captions" src="audit-fr.vtt" srclang="fr" label="Français" default />
</video> L’attribut controls fournit une barre complète : lecture et pause, son,
volume, position, sous-titres, plein écran. Chaque contrôle y est un vrai
bouton ou un vrai curseur, focalisable, nommé, avec son état exposé — sans une
ligne de script, et sans que rien ne se dégrade quand le navigateur change.
La question à se poser avant d’écrire un lecteur n’est donc pas « comment le rendre accessible » mais « qu’est-ce que la barre native ne fait pas ». Si la réponse tient dans la couleur des boutons, un peu de CSS coûtera moins qu’un composant à maintenir.
2. Le minimum exigé d’un lecteur maison
Le référentiel ne laisse pas la liste au jugement : le glossaire « contrôle de la consultation » énumère les fonctionnalités obligatoires. Un objet multimédia doit toujours avoir, au minimum, lecture, et pause ou stop. S’il a du son, une activation / désactivation du son. S’il a des sous-titres non incrustés, un contrôle de leur apparition / disparition. S’il a une audiodescription, le même contrôle pour elle.
Le volume, la position et le plein écran n’y figurent pas : ce sont de bonnes choses à offrir, pas des obligations. Mais l’exigence de clavier, elle, porte sur chaque fonctionnalité présente — le critère 4.11 dit « chaque fonctionnalité », pas « chaque fonctionnalité obligatoire ». Un contrôle ajouté est un contrôle à rendre atteignable et activable.
3. Des boutons natifs, et un nom qui dit l’action
<button type="button" id="lecture">Pause</button>
<button type="button" aria-pressed="true">Sous-titres</button> Deux façons d’exposer un état, et il faut choisir laquelle par bouton.
Quand les deux états correspondent à deux actions différentes, le nom
change : « Lecture » devient « Pause », « Couper le son » devient « Rétablir le
son ». Quand il s’agit d’une option qu’on active ou non, le nom reste et aria-pressed porte l’état : « Sous-titres, activé ».
Ce qu’il ne faut jamais faire, c’est les deux à la fois. Un bouton nommé
« Pause » et marqué aria-pressed="true" s’annonce « Pause, bouton pressé » —
deux informations qui se contredisent, et un utilisateur qui ne sait plus si la
prochaine pression lance ou arrête.
Si le bouton n’affiche qu’un pictogramme, son nom vient d’aria-label et le
pictogramme porte aria-hidden="true". Un title seul ne suffit pas : il
n’apparaît qu’au survol de la souris.
4. La barre de progression est un curseur
Le plus court chemin est l’élément natif, qui donne le rôle, les valeurs, les flèches, Début et Fin d’un seul coup :
<label class="sr-only" for="position">Position dans la vidéo</label>
<input
id="position"
type="range"
min="0"
max="30"
step="1"
value="12"
aria-valuetext="12 secondes sur 30 secondes"
/> aria-valuetext est ici l’attribut qui change tout. Sans lui, le lecteur
d’écran annonce « 12 » — douze quoi, sur quoi ? Avec lui, il annonce une durée,
qui est ce que l’utilisateur cherche.
Si la barre doit être dessinée à la main, le contrat est plus long, et il est entièrement à votre charge :
<div
role="slider"
tabindex="0"
aria-label="Position dans la vidéo"
aria-valuemin="0"
aria-valuemax="30"
aria-valuenow="12"
aria-valuetext="12 secondes sur 30 secondes"
></div> Il reste alors à écrire le clavier : ← → pour un pas,
Début et Fin pour les extrémités, et un saut plus large sur Page préc. et Page suiv.. Et à ne pas oublier ce que prévoit le glossaire [« accessible et activable par le clavier et tout dispositif de pointage »](/glossaire/accessible-et-activable-par-le-clavier-et-tout-dispositif-de-pointage) : pour un curseur, « il n'est pas possible de contrôler le composant par la seule touche d'entrée. Dans ces situations, d'autres touches (comme les touches de direction) peuvent être utilisées. »5. Le temps écoulé ne va dans aucune région live
<!-- À ne pas faire -->
<span aria-live="polite">0:12</span> Une seconde, une annonce. La restitution devient un compteur qui parle sans
arrêt et qui recouvre tout le reste : le nom du bouton qu’on vient d’atteindre,
le message d’erreur, la page entière. Le temps se demande — il est déjà dans
l’aria-valuetext de la barre, disponible à la lecture, imposé à personne.
6. Les sous-titres : <track kind="captions">
<track kind="captions" src="audit-fr.vtt" srclang="fr" label="Français" default /> Le test 4.3.2 attend kind="captions", et pas kind="subtitles". La
distinction n’est pas cosmétique : les subtitles traduisent les dialogues
pour qui n’entend pas la langue, les captions portent en plus les sons
signifiants — la porte qui claque, la musique qui monte. Ce sont ces derniers
que le référentiel demande.
Un lecteur maison peut garder l’élément <video> et laisser le navigateur
rendre les pistes ; s’il dessine les sous-titres lui-même à partir de l’API TextTrack, il doit aussi refaire le bouton qui les coupe — c’est le contrôle
d’apparition / disparition exigé au point 2.
Au clavier
| Touche | Effet |
|---|---|
| Tab | Passe au contrôle suivant du lecteur. Aucun n’est sauté, y compris les curseurs. |
| Entrée / Espace | Active le bouton qui a le focus. Le focus y reste, et le bouton porte désormais le nom de l’action suivante. |
| ← → | Sur la barre de progression, recule ou avance d’un pas. Sur le volume, baisse ou monte. |
| Début / Fin | Sur un curseur, va au minimum ou au maximum — début du média, ou volume plein. |
| Page préc. / Page suiv. | Sur un curseur, saut plus large, donné par le navigateur sur <input type="range">. |
Ce que le lecteur d’écran restitue
Sur le bouton de lecture : le nom et la nature — « Lecture, bouton ». Après activation, le nom du bouton devient « Pause, bouton » : qui y revient, ou l’atteint à nouveau, entend l’état courant. Que le nouveau nom soit réannoncé immédiatement, sans que le focus bouge, dépend du lecteur d’écran — NVDA le fait, d’autres non ; c’est le nom exposé qui est la garantie, pas l’annonce.
Sur la barre de progression : « Position dans la vidéo, curseur, 12 secondes sur 30 secondes ». Sur le bouton de sous-titres, le nom ne bouge pas et l’état s’ajoute : « Sous-titres, bouton, activé ». La formulation varie d’un lecteur à l’autre — pas les informations.
Si vous entendez « curseur, 12 », aria-valuetext manque. Si vous n’entendez
rien du tout sur un bouton, il n’a pas de nom : une icône seule, sans aria-label. Si vous entendez « Pause, bouton pressé », le bouton cumule un
nom qui change et un aria-pressed. Et si le nom ne change jamais, l’état de
lecture n’est exposé nulle part.
Checklist
- Essayez
<video controls>avant d’écrire un lecteur. - Lecture et pause, activation du son, affichage des sous-titres : le minimum exigé, au clavier comme au pointeur.
- Des
<button>natifs ; un nom qui change, ouaria-pressed— jamais les deux. - La barre de progression est un curseur :
<input type="range">, ourole="slider"avec ses quatre valeurs et son clavier. aria-valuetextpour dire une durée, jamais un nombre nu.- Le temps écoulé hors de toute région
aria-live. - Une barre de contrôle qui s’efface ne doit pas emporter le focus avec elle.
Les critères RGAA en jeu
- Critère 4.11 — Contrôle des médias temporels
Un lecteur maison remplace des contrôles natifs qui fonctionnaient : lecture, pause, activation du son et affichage des sous-titres doivent rester atteignables et activables au clavier comme au pointeur.
- Critère 4.13 — Compatibilité des médias
Chaque contrôle doit exposer son nom, son rôle et sa valeur. Une barre de progression dessinée en div ne dit ni qu'elle est un curseur, ni où l'on en est, ni jusqu'où l'on peut aller.
- Critère 4.3 — Sous-titres synchronisés
Les sous-titres se diffusent par un élément track, et le référentiel y attend kind=captions : une piste déclarée en subtitles ne porte pas les sons signifiants et ne vaut pas sous-titrage.
- Critère 7.3 — Contrôle des scripts au clavier
La barre de contrôle qui s'efface après quelques secondes retire du document le bouton qui avait le focus : le script supprime le focus, et le clavier repart du haut de la page.
Vérifiez votre composant avec l'extension
Pour aller plus loin
- Critère 4.11 — Contrôle des médias temporels et 4.13 — Compatibilité des médias : les deux critères qu’un audit applique à tout lecteur.
- « Contrôle de la consultation » au glossaire : la liste limitative des fonctionnalités obligatoires.
- « Média temporel » au glossaire : la définition qui décide si le thème 4 s’applique à votre contenu.
- La modale : le passage en plein écran pose le même problème de focus enfermé dans une zone, et se règle de la même façon.
Sources
- ARIA APG — Slider Pattern — le contrat de comportement d’une barre de progression manipulable
- MDN —
<video>— l’élément et son attributcontrols - MDN —
<track>— les pistes de sous-titres et leurskind - WCAG — Understanding 2.1.1 Keyboard — l’exigence de fonctionnement au clavier
- W3C WAI — Making Audio and Video Media Accessible — le tutoriel de référence sur les médias