Le champ de recherche
Un placeholder n'est pas une étiquette, une loupe n'est pas un nom. Le champ de recherche est le cas où le référentiel a prévu qu'aucune étiquette ne soit visible — à des conditions précises, qu'il faut lire. Démo, code, critères RGAA.
6 critères RGAA en jeu
Essayez-le
Tapez un mot et validez avec Entrée depuis le champ : c’est le <form> qui donne ce raccourci, et le nombre de résultats est annoncé sans
qu’on ait à le chercher. Le champ n’affiche aucune étiquette — le second bouton
inspecte le formulaire réel et montre d’où vient tout de même son nom.
Cette démo existe aussi en page autonome.
L’erreur courante
Un champ étiqueté par son seul placeholder, et un bouton qui ne porte qu’une loupe.
<!-- À ne pas faire -->
<div class="recherche">
<input type="text" placeholder="Rechercher" />
<button type="submit"><img src="/img/loupe.svg" /></button>
</div> Trois pertes, dans trois registres différents.
Le champ n’a pas d’étiquette. À l’arrivée du focus, on entend bien « Rechercher, zone de saisie » : le placeholder sert de dernier recours au calcul du nom accessible. Mais il disparaît dès la première frappe — le nom s’évapore au moment où l’on en aurait besoin pour se relire — et le référentiel ne le compte pas parmi les façons d’étiqueter un champ (glossaire « Étiquette de champ de formulaire »).
Le bouton n’a pas de nom non plus. L’image sans alt ne fournit aucun
intitulé ; selon le navigateur, on entend « bouton » seul, ou le nom du
fichier. La fonction la plus importante du composant est devenue anonyme.
La zone n’existe pas pour la navigation par repères. Un div ne désigne
rien : la seule façon d’atteindre la recherche est de tabuler jusqu’à elle,
depuis le début de la page, à chaque page.
Trois variantes, plus discrètes :
aria-label="Rechercher"sur le champ, avec un bouton en loupe seule. Le nom existe, mais plus aucun texte n’est visible près du champ : le test 11.1.3 réclame alors untitle, ou un passage de texte visible accolé au champ, ou un passage qui devient visible à la prise de focus.- Un
div role="search"autour d’un champ et d’un bouton, sans<form>. Entrée dans le champ ne lance plus rien : il faut atteindre le bouton pour chercher. - Le champ replié derrière une icône sur les pages intérieures, déplié en en-tête sur l’accueil. La fonctionnalité change de nature d’une page à l’autre — c’est exactement ce que le critère 12.5 refuse.
Le code, pas à pas
1. Un formulaire, et un repère
<form role="search" action="/recherche">…</form> Le formulaire est la zone de recherche : il n’y a pas de conteneur à ajouter
autour. role="search" le fait apparaître dans la liste des repères, celle
qu’un lecteur d’écran parcourt d’une touche.
L’élément natif <search> produit le même repère sans attribut. Il est récent ;
le rôle explicite est celui que les technologies d’assistance connaissent depuis
le plus longtemps. Choisissez l’un ou l’autre : les deux ensemble font
doublon.
Le critère 12.6 n’impose pas ce repère. Il accepte aussi un titre qui nomme la zone, un lien d’évitement, un lien d’accès rapide ou un bouton de masquage. Le repère est simplement celui qui ne coûte qu’un attribut.
S’il y a deux zones de recherche dans la page — le moteur du site et celle d’un
catalogue —, nommez-les : aria-label="Rechercher dans le site". Deux repères
identiques ne se distinguent pas dans une liste.
2. L’étiquette, visible ou non
Le cas par défaut reste le plus simple :
<label for="recherche">Rechercher dans le site</label>
<input id="recherche" type="search" /> Mais un champ de recherche affiche rarement son étiquette, et le référentiel a prévu ce cas. Le test 11.1.1 accepte, parmi ses conditions, celle-ci :
Un bouton adjacent au champ de formulaire lui fournit une étiquette visible et un élément
<label>visuellement caché ou un attribut WAI-ARIAaria-label,aria-labelledbyoutitlelui fournit un nom accessible.
Deux choses, donc, et pas une seule :
<form role="search">
<label for="recherche" class="sr-only">Rechercher dans le site</label>
<input id="recherche" type="search" />
<button type="submit">Rechercher</button>
</form> Le bouton porte le texte visible qui dit à l’œil ce qu’est ce champ, et il
est adjacent — voisin immédiat dans le rendu et dans le code source, comme
le glossaire le définit. Le <label> masqué porte le nom accessible, que la
classe sr-only retire de l’affichage sans le retirer de l’arbre.
Retirez le texte du bouton, et la condition tombe : il ne reste plus rien de
visible, et le test 11.1.3 demande alors un title sur le champ ou un texte
accolé. C’est le lien direct entre les deux erreurs les plus courantes de ce
composant.
3. type="search", pour ce qu’il donne vraiment
<input id="recherche" type="search" name="q" /> Il apporte le contrôle d’effacement des navigateurs qui en proposent un, et un
clavier virtuel dont la touche de validation porte « rechercher ». Il ne fournit aucun nom : le type n’est pas une étiquette, et le champ sans <label> reste
sans nom quel que soit son type.
4. Le bouton, même s’il ne porte qu’une loupe
<button type="submit">
<svg aria-hidden="true" focusable="false">…</svg>
Rechercher
</button> La loupe est un doublon visuel du mot : masquée par aria-hidden, elle n’a rien
à annoncer en plus. Le texte, lui, sert deux fois — comme intitulé du bouton
(critère 11.9) et comme étiquette visible du champ (critère 11.1).
Si la place manque vraiment et que le bouton se réduit à l’icône, le nom se donne autrement — et il faut alors régler la question de l’étiquette visible, vue au point 2 :
<button type="submit">
<svg aria-hidden="true" focusable="false">…</svg>
<span class="sr-only">Rechercher</span>
</button> Le texte masqué se préfère à un aria-label : il est traduit par les outils de
traduction automatique, ce qu’un attribut n’est pas toujours. Les deux
satisfont le test 11.9.1, qui accepte le contenu du <button>, l’aria-label,
l’aria-labelledby, le value d’un <input>, l’alt d’un bouton image ou le title.
5. Les résultats s’annoncent
Quand la recherche s’affiche sans changer de page, le compte est un message de statut :
<!-- Présente dès le chargement, vide, et remplie plus tard -->
<p role="status"></p> La région doit exister avant l’annonce. Créée au moment où le résultat arrive, elle n’est pas restituée par tous les lecteurs d’écran — et l’on obtient alors une recherche qui semble ne rien faire.
Annoncez le nombre, pas la liste : « 3 résultats pour « onglets » » suffit à savoir qu’il faut aller lire, et une liste entière lue à voix haute dans une région d’annonce est ingérable.
6. Le même moteur, à la même place
Le critère 12.5 porte sur l’ensemble des pages, pas sur une seule : la même fonctionnalité, à la même place dans la présentation, dans le même ordre relatif dans le code source. C’est le critère qu’on casse en refactorant un en-tête, et que rien ne signale sur la page qu’on regarde.
Au clavier
| Touche | Effet |
|---|---|
| Tab | Entre dans le champ, puis va au bouton de soumission. |
| Entrée | Depuis le champ, soumet le formulaire — comportement du <form>, qu’un div ne donne pas. |
| Entrée / Espace | Sur le bouton, lance la recherche. |
| Navigation par repères | Atteint la zone de recherche sans tabuler depuis le haut de la page (D sous NVDA, R sous JAWS). |
Ce que le lecteur d’écran restitue
À l’entrée dans la zone, puis dans le champ : le repère, le nom, la nature — de l’ordre de « recherche, repère — Rechercher dans le site, champ de recherche ». Sur le bouton : « Rechercher, bouton ». La formulation varie d’un lecteur à l’autre, les informations non.
Si le nom que vous entendez disparaît dès que vous tapez une lettre, c’est le
placeholder qui le fournissait : ce n’est pas une étiquette. Et si vous
n’entendez que « zone de saisie, vide », rien du tout ne nomme le champ.
Si vous n’entendez que « bouton », la loupe n’a
pas d’alternative textuelle. Et si la liste des repères de la page ne contient
pas « recherche », c’est que le role="search" ou l’élément <search> manque.
Checklist
- Un
<form>— pas undiv— porteur du repère de recherche, nommé s’il y en a deux. - Une
<label>liée au champ ; le placeholder reste un exemple, jamais l’étiquette. - Étiquette masquée : un texte visible accolé, celui du bouton, ou à défaut un
title. - Le bouton nommé même réduit à une loupe ; le glyphe en
aria-hidden="true". type="search"sur le champ, pour l’effacement et le clavier mobile.- Le nombre de résultats dans une région
role="status"présente dès le chargement. - Le même moteur, à la même place, dans le même ordre du code, sur toutes les pages.
Les critères RGAA en jeu
- Critère 11.1 — Étiquette de champ de formulaire
C'est le champ qu'on livre le plus souvent sans étiquette : le placeholder occupe la place, et le seul nom du champ s'efface à la première frappe.
- Critère 11.2 — Pertinence de l’étiquette
L'étiquette doit dire la fonction exacte du champ. Sur un site qui porte un moteur global et la recherche d'un catalogue, deux « Rechercher » identiques ne distinguent plus rien.
- Critère 11.9 — Intitulé des boutons
Le bouton ne montre souvent qu'une loupe. Sans contenu textuel, sans aria-label et sans alt, son intitulé est vide : le lecteur d'écran annonce « bouton », et c'est tout.
- Critère 12.6 — Zones de regroupement atteignables
La zone de moteur de recherche fait partie des cinq zones qui doivent pouvoir être atteintes ou évitées ; le repère de recherche est la façon la moins coûteuse d'y répondre.
- Critère 12.5 — Accès au moteur de recherche
Le moteur doit s'atteindre partout de la même manière : même fonctionnalité, même place dans la présentation, même ordre relatif dans le code source d'une page à l'autre.
- Critère 7.5 — Messages de statut
Le nombre de résultats s'affiche sans changement de page. Sans région d'annonce présente d'avance, la personne qui a lancé la recherche ne sait pas qu'elle a abouti.
Vérifiez votre composant avec l'extension
Pour aller plus loin
- Les champs de formulaire : l’étiquette, l’aide et l’erreur, quand l’étiquette peut rester visible.
- Critère 11.1 — Étiquette de champ et 12.6 — Zones de regroupement : ce qu’un audit vérifie ici, test par test.
- « Moteur de recherche (interne à un site web) » au glossaire : la définition qui décide de ce qui relève des critères 12.5 et 12.6.
- « Lien ou bouton adjacent » au glossaire : ce qu’« adjacent » veut dire exactement, dans le rendu et dans le code.
Sources
- ARIA APG — Search Landmark — ce que le repère désigne, et combien il en faut par page
- MDN —
<search>— l’élément natif qui porte le repère - W3C WAI — Forms Tutorial: Labeling Controls — le cas du champ sans étiquette visible, traité de front
- WCAG — Understanding 3.3.2 Labels or Instructions — pourquoi un champ doit dire ce qu’il attend