Les articles précédents ont posé les bases théoriques. Celui-ci est opérationnel : huit composants courants sur les sites WordPress Full Site Editing (FSE), avec pour chacun le HTML minimal conforme, les annonces exactes de NVDA, les erreurs fréquentes en audit, et les spécificités des blocs natifs Gutenberg.
Chaque pattern suit la même structure :
- HTML conforme : la structure minimale correcte
- Ce que NVDA annonce : transcription exacte sur Firefox
- Erreurs fréquentes : ce qu’on observe en audit
- Spécificité WordPress FSE : comportement du bloc natif et corrections
1. Menu de navigation avec sous-menus
Le composant le plus audité, le plus souvent incorrect.
HTML conforme
<nav aria-label="Navigation principale">
<ul>
<li>
<a href="/" aria-current="page">Accueil</a>
</li>
<li>
<a href="/mairie"
aria-haspopup="true"
aria-expanded="false"
aria-controls="sous-menu-mairie"
id="lien-mairie">
Mairie
</a>
<ul id="sous-menu-mairie" role="list">
<li><a href="/mairie/conseil">Conseil municipal</a></li>
<li><a href="/mairie/horaires">Horaires d'accueil</a></li>
</ul>
</li>
</ul>
</nav>
Ce que NVDA annonce
[Navigation au landmark navigation]
→ "Navigation principale, navigation, région de repère"
[Tab sur "Accueil"]
→ "Accueil, page actuelle, lien"
[Tab sur "Mairie"]
→ "Mairie, sous-menu, réduit, lien"
[Entrée sur "Mairie" — ouverture du sous-menu]
→ "Mairie, sous-menu, développé, lien"
[Tab sur "Conseil municipal"]
→ "Conseil municipal, lien"
Erreurs fréquentes en audit
role="menu" sur <ul> de navigation : impose un comportement clavier (flèches) que les utilisateurs n’attendent pas sur une navigation de site. Utiliser simplement <ul> sans rôle.
aria-current absent sur le lien actif : l’état actif est visible visuellement (CSS .current-menu-item) mais muet pour les AT.
Plusieurs <nav> sans aria-label distinct : dans la liste des landmarks, l’utilisateur entend “navigation, navigation, navigation” sans pouvoir distinguer principale, pied de page, fil d’ariane, etc.
Sous-menu ouvert sans mise à jour d’aria-expanded : le bouton dit “réduit” mais le menu est visible. Désynchronisation état ARIA / état réel.
Spécificité WordPress FSE
Le bloc Navigation (core/navigation) génère nativement aria-label sur le <nav> via l’option “Étiquette ARIA” dans l’inspecteur de bloc. À vérifier que cette option est renseignée, elle est vide par défaut.
aria-current="page" est généré automatiquement par WordPress sur le lien actif depuis la version 6.1. À vérifier dans les thèmes enfants qui surchargent wp_nav_menu().
Pour les sous-menus, les blocs Interactivity API (WordPress 6.5+) gèrent aria-expanded nativement. Les versions antérieures nécessitent un script personnalisé ou un plugin (Accessibility Checker, WP Accessibility).
Critères RGAA : 6.1 , 6.2 , 7.1 , 7.3 , 9.2 , 12.6 , 12.7 .
2. Bouton burger (menu mobile)
HTML conforme
<!-- Le bouton -->
<button
type="button"
aria-label="Ouvrir le menu"
aria-expanded="false"
aria-controls="menu-principal"
>
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M3 12h18M3 6h18M3 18h18" stroke="currentColor" stroke-width="2"/>
</svg>
</button>
<!-- Le menu contrôlé -->
<nav id="menu-principal" aria-label="Navigation principale" hidden>
<ul>
<li><a href="/">Accueil</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
const btn = document.querySelector('[aria-controls="menu-principal"]');
const menu = document.getElementById('menu-principal');
btn.addEventListener('click', () => {
const estOuvert = btn.getAttribute('aria-expanded') === 'true';
btn.setAttribute('aria-expanded', String(!estOuvert));
btn.setAttribute('aria-label', estOuvert ? 'Ouvrir le menu' : 'Fermer le menu');
if (estOuvert) {
menu.setAttribute('hidden', '');
} else {
menu.removeAttribute('hidden');
// Déplacer le focus sur le premier lien du menu
menu.querySelector('a')?.focus();
}
});
// Fermeture sur Échap
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && btn.getAttribute('aria-expanded') === 'true') {
btn.setAttribute('aria-expanded', 'false');
btn.setAttribute('aria-label', 'Ouvrir le menu');
menu.setAttribute('hidden', '');
btn.focus(); // retour au déclencheur
}
});
Ce que NVDA annonce
[Tab sur le bouton burger, menu fermé]
→ "Ouvrir le menu, bouton réduit"
[Entrée — ouverture]
→ "Fermer le menu, bouton développé"
→ [focus déplacé] "Accueil, lien"
[Échap — fermeture]
→ [focus retourné au bouton] "Ouvrir le menu, bouton réduit"
Erreurs fréquentes en audit
aria-label statique : le bouton dit “Ouvrir le menu” même quand le menu est ouvert. Mettre à jour le label en même temps qu’aria-expanded.
Icône SVG sans aria-hidden : si le SVG a un <title>, NVDA peut annoncer à la fois le <title> et l’aria-label du bouton. Toujours aria-hidden="true" focusable="false" sur les SVG décoratifs.
Focus non déplacé à l’ouverture : l’utilisateur ouvre le menu et son focus reste sur le bouton. Il doit tabber manuellement jusqu’aux liens. Déplacer le focus sur le premier item du menu.
Focus non restauré à la fermeture : l’utilisateur ferme le menu (Échap ou clic) et son focus disparaît. Le retourner au bouton déclencheur.
Spécificité WordPress FSE
Le bloc Navigation inclut un bouton burger natif activé via l’option “Afficher le bouton de menu mobile” dans l’inspecteur. Il génère aria-expanded mais pas toujours aria-label explicite, vérifier le rendu HTML dans les DevTools. Le comportement focus (déplacement à l’ouverture, retour à la fermeture) dépend du thème FSE.
3. Accordéon
HTML conforme
<div class="accordeon">
<h3>
<button
type="button"
aria-expanded="false"
aria-controls="panneau-1"
id="btn-1"
>
Quels sont les horaires d'ouverture ?
</button>
</h3>
<div id="panneau-1" role="region" aria-labelledby="btn-1" hidden>
<p>Lundi au vendredi, 9h-17h. Fermé le mercredi après-midi.</p>
</div>
<h3>
<button
type="button"
aria-expanded="false"
aria-controls="panneau-2"
id="btn-2"
>
Comment prendre rendez-vous ?
</button>
</h3>
<div id="panneau-2" role="region" aria-labelledby="btn-2" hidden>
<p>Par téléphone au 02 98 XX XX XX ou en ligne.</p>
</div>
</div>
Ce que NVDA annonce
[Tab sur le premier bouton, accordéon fermé]
→ "Quels sont les horaires d'ouverture ?, bouton réduit"
[Entrée — ouverture]
→ "Quels sont les horaires d'ouverture ?, bouton développé"
[Tab — entrée dans le panneau]
→ "Quels sont les horaires d'ouverture ?, région"
→ "Lundi au vendredi, 9h-17h. Fermé le mercredi après-midi."
Erreurs fréquentes en audit
<div> à la place de <button> : un <div class="accordeon-titre"> avec onclick n’est pas focusable, pas activable au clavier, non annoncé comme bouton. Utiliser <button> ou <a>.
aria-expanded sur le panneau plutôt que sur le déclencheur : le lecteur d’écran n’annonce l’état que sur l’élément où se trouve le focus.
Titre absent : le bouton sans <h2>, <h3>… fait partie du contenu mais n’apparaît pas dans la navigation par titres (touche H dans NVDA). Envelopper le bouton dans un titre de niveau approprié.
role="region" sans label : role="region" sans aria-labelledby ne génère pas de landmark. Inutile de l’ajouter si le panneau n’a pas de label.
Spécificité WordPress FSE
WordPress FSE intègre un bloc Accordéon natif depuis WordPress 6.8 (Interactivity API). Le markup généré est de bonne qualité :
<button type="button">dans un<h3>, sémantique correcte, présent dans la navigation par titresaria-expandedmis à jour dynamiquement viadata-wp-bind--aria-expanded- Panneau masqué avec l’attribut
inert: bloque à la fois le focus clavier et la lecture AT, plus fiable que hidden seul aria-expanded+aria-labelledbysur le panneau, landmark nommé
Point à surveiller en audit : aria-labelledby sur le panneau référence l’id du bouton entier, pas seulement le span du titre. NVDA peut annoncer le nom complet du bouton comme label de la région (verbeux mais conforme). À tester avec NVDA + Firefox sur le site réel.
Prérequis : le bloc natif nécessite l’Interactivity API (WordPress 6.5+) et JavaScript activé. Sans JS, aria-expanded reste à sa valeur initiale, vérifier le comportement en JS désactivé si la conformité totale est requise.
Pour les sites sur WordPress < 6.8, les plugins (Stackable, Kadence Blocks) restent nécessaires : vérifier systématiquement que le déclencheur est un <button> et qu’aria-expanded est mis à jour au clic.
4. Interface à onglets
HTML conforme
<div class="onglets">
<div role="tablist" aria-label="Sections du dossier">
<button
role="tab"
id="tab-infos"
aria-selected="true"
aria-controls="panel-infos"
>
Informations
</button>
<button
role="tab"
id="tab-docs"
aria-selected="false"
aria-controls="panel-docs"
tabindex="-1"
>
Documents
</button>
<button
role="tab"
id="tab-contact"
aria-selected="false"
aria-controls="panel-contact"
tabindex="-1"
>
Contact
</button>
</div>
<div role="tabpanel" id="panel-infos" aria-labelledby="tab-infos">
<p>Informations générales…</p>
</div>
<div role="tabpanel" id="panel-docs" aria-labelledby="tab-docs" hidden>
<p>Documents disponibles…</p>
</div>
<div role="tabpanel" id="panel-contact" aria-labelledby="tab-contact" hidden>
<p>Coordonnées…</p>
</div>
</div>
Navigation clavier obligatoire :
Tab: entre dans la liste d’onglets, se pose sur l’onglet sélectionné←→: navigation entre onglets (pasTab)EntréeouEspace: sélectionne l’onglet et affiche le panneauTabdepuis un onglet : saute directement au panneau actif
Ce que NVDA annonce
[Tab — entrée dans le tablist]
→ "Sections du dossier, barre d'onglets"
→ "Informations, onglet sélectionné, 1 sur 3"
[→ flèche droite]
→ "Documents, onglet, 2 sur 3"
[Entrée — sélection]
→ "Documents, onglet sélectionné, 2 sur 3"
[Tab — saut au panneau]
→ "Documents, panneau d'onglet"
→ "Documents disponibles…"
Erreurs fréquentes en audit
Navigation aux onglets avec Tab au lieu des flèches : crée des pièges clavier. Les onglets non sélectionnés doivent avoir tabindex="-1".
aria-selected absent sur les onglets non sélectionnés : ne pas omettre aria-selected="false". Sans lui, NVDA n’annonce pas l’état des onglets non actifs.
Panneaux sans aria-labelledby : les panneaux ne sont pas identifiés. L’utilisateur arrive dans un panneau sans savoir à quel onglet il correspond.
Focus non déplacé au panneau après sélection : l’utilisateur active un onglet et son focus reste sur le bouton. Il doit tabber pour atteindre le contenu.
Spécificité WordPress FSE
Aucun bloc onglets natif dans Gutenberg. Les plugins (Stackable, Kadence Blocks) implémentent souvent les onglets avec <div> cliquables et navigation à Tab (non conforme). Vérifier systématiquement le comportement clavier et l’implémentation ARIA.
5. Fenêtre modale (dialog)
HTML conforme
<!-- Déclencheur -->
<button type="button" aria-haspopup="dialog" id="btn-ouvrir-modal">
Voir les conditions d'utilisation
</button>
<!-- Modale -->
<div
role="dialog"
aria-labelledby="titre-modal"
aria-describedby="desc-modal"
aria-modal="true"
id="modal"
hidden
>
<h2 id="titre-modal">Conditions d'utilisation</h2>
<p id="desc-modal">Veuillez lire et accepter les conditions avant de continuer.</p>
<div class="contenu-modal">
<p>Lorem ipsum…</p>
</div>
<div class="actions-modal">
<button type="button" id="btn-accepter">Accepter</button>
<button type="button" id="btn-fermer">Fermer</button>
</div>
</div>
<!-- Fond semi-transparent -->
<div class="overlay" hidden aria-hidden="true"></div>
Gestion du focus obligatoire :
const modal = document.getElementById('modal');
const btnOuvrir = document.getElementById('btn-ouvrir-modal');
const btnFermer = document.getElementById('btn-fermer');
// Éléments focusables dans la modale
const focusables = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
function ouvrirModal() {
modal.removeAttribute('hidden');
document.getElementById('overlay').removeAttribute('hidden');
// Piéger le focus dans la modale
modal.addEventListener('keydown', piegerFocus);
// Focus sur le premier élément interactif
modal.querySelector(focusables)?.focus();
}
function fermerModal() {
modal.setAttribute('hidden', '');
document.getElementById('overlay').setAttribute('hidden', '');
modal.removeEventListener('keydown', piegerFocus);
// Retour au déclencheur
btnOuvrir.focus();
}
function piegerFocus(e) {
if (e.key !== 'Tab') return;
const elements = [...modal.querySelectorAll(focusables)];
const premier = elements[0];
const dernier = elements[elements.length - 1];
if (e.shiftKey && document.activeElement === premier) {
e.preventDefault();
dernier.focus();
} else if (!e.shiftKey && document.activeElement === dernier) {
e.preventDefault();
premier.focus();
}
}
// Fermeture sur Échap
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && !modal.hasAttribute('hidden')) fermerModal();
});
btnOuvrir.addEventListener('click', ouvrirModal);
btnFermer.addEventListener('click', fermerModal);
Ce que NVDA annonce
[Ouverture de la modale]
→ "Conditions d'utilisation, boîte de dialogue"
→ "Veuillez lire et accepter les conditions avant de continuer."
→ [focus sur premier bouton] "Accepter, bouton"
[Tab dans la modale]
→ Navigation entre Accepter, Fermer — puis retour à Accepter
[Échap]
→ [focus retourné] "Voir les conditions d'utilisation, bouton boîte de dialogue"
Erreurs fréquentes en audit
Focus non piégé : l’utilisateur clavier peut sortir de la modale et interagir avec le contenu en arrière-plan. Erreur critique.
Focus non déplacé à l’ouverture : le focus reste sur le bouton déclencheur. L’utilisateur doit deviner qu’une modale s’est ouverte.
Focus non restauré à la fermeture : le focus se perd, souvent renvoyé au début de la page.
aria-modal="true" seul sans gestion du focus : aria-modal indique aux AT que le fond est inerte, mais ne piège pas réellement le focus. La gestion JavaScript reste obligatoire.
Fond semi-transparent focusable : l’overlay cliquable pour fermer doit avoir aria-hidden="true" et ne pas être dans l’ordre de tabulation.
Spécificité WordPress FSE
Le bloc natif <dialog> HTML5 (supporté par Chrome 37+, Firefox 98+, Safari 15.4+) simplifie l’implémentation. Les plugins de lightbox et de modale (FancyBox, Popup Maker) gèrent rarement le focus correctement (vérifier systématiquement).
Critères RGAA : 7.1 , 7.3 , 7.4 .
6. Carrousel et diaporama
Le composant le plus complexe à rendre accessible, et le plus fréquent sur les sites publics.
HTML conforme minimal
<section
aria-label="Photos de la commune"
aria-roledescription="carrousel"
>
<!-- Contrôles -->
<div class="controles-carrousel">
<button type="button" aria-label="Diapositive précédente" id="btn-prev">
<svg aria-hidden="true" focusable="false"><!-- flèche gauche --></svg>
</button>
<button type="button" aria-label="Pause du carrousel" id="btn-pause">
<svg aria-hidden="true" focusable="false"><!-- pause --></svg>
</button>
<button type="button" aria-label="Diapositive suivante" id="btn-next">
<svg aria-hidden="true" focusable="false"><!-- flèche droite --></svg>
</button>
</div>
<!-- Piste de diapositives -->
<div
aria-live="polite"
aria-atomic="false"
class="piste-carrousel"
>
<div
role="group"
aria-roledescription="diapositive"
aria-label="1 sur 5"
aria-hidden="false"
>
<img src="photo-1.jpg" alt="Vue du port de Primelin au coucher du soleil">
</div>
<div
role="group"
aria-roledescription="diapositive"
aria-label="2 sur 5"
aria-hidden="true"
>
<img src="photo-2.jpg" alt="La chapelle Saint-Tugen en automne">
</div>
</div>
<!-- Indicateurs de position -->
<div role="group" aria-label="Choisir une diapositive">
<button aria-label="Diapositive 1" aria-current="true"></button>
<button aria-label="Diapositive 2"></button>
</div>
</section>
Ce que NVDA annonce
[Entrée dans la section]
→ "Photos de la commune, carrousel"
[Tab sur le bouton précédent]
→ "Diapositive précédente, bouton"
[Changement automatique de diapositive]
→ "2 sur 5, diapositive" (annonce polite — attend fin lecture)
[Tab sur l'image]
→ "La chapelle Saint-Tugen en automne, image"
Erreurs fréquentes en audit
Pas de bouton pause : si le carrousel défile automatiquement, un contrôle pause/lecture accessible au clavier est obligatoire (critère 13.1 et 13.8).
Images sans alt : les diapositives sont des images porteuses d’information. alt="" est une NC sévère sur un carrousel de patrimoine.
aria-live="assertive" sur la piste : interrompt le lecteur d’écran à chaque changement. Utiliser "polite" pour les carrousels.
Défilement automatique sans prefers-reduced-motion : les utilisateurs sensibles aux animations peuvent désactiver les effets. Respecter cette préférence.
@media (prefers-reduced-motion: reduce) {
.carrousel-auto { animation: none; }
}
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
clearInterval(intervalAuto);
}
Spécificité WordPress FSE
Le bloc Galerie (core/gallery) ne génère pas de carrousel, il crée une grille d’images statiques, accessible si les alt sont renseignés. Les carrousels viennent de plugins (Easing Slider, Soliloquy, Smart Slider). Ces plugins génèrent rarement aria-roledescription, aria-live, ou des boutons pause accessibles. La recommandation en audit : préférer une galerie statique à un carrousel automatique.
Critères RGAA : 1.1 , 7.1 , 7.3 , 13.1 , 13.8 .
7. Formulaire avec validation
HTML conforme
<form novalidate>
<p>Les champs marqués d'un <span aria-hidden="true">*</span>
<span class="sr-only">astérisque</span> sont obligatoires.</p>
<!-- Zone d'erreurs globales — live region -->
<div role="alert" id="erreurs-globales" aria-label="Erreurs dans le formulaire"></div>
<!-- Champ texte avec aide et erreur -->
<div class="champ">
<label for="nom">
Nom <span aria-hidden="true">*</span>
</label>
<input
type="text"
id="nom"
name="nom"
autocomplete="family-name"
aria-required="true"
aria-describedby="aide-nom erreur-nom"
aria-invalid="false"
>
<p id="aide-nom" class="aide">Votre nom de famille tel qu'il apparaît sur vos documents officiels.</p>
<p id="erreur-nom" role="alert" class="erreur" hidden>
Le nom est obligatoire.
</p>
</div>
<!-- Champ email -->
<div class="champ">
<label for="email">
Adresse email <span aria-hidden="true">*</span>
</label>
<input
type="email"
id="email"
name="email"
autocomplete="email"
aria-required="true"
aria-describedby="erreur-email"
aria-invalid="false"
>
<p id="erreur-email" role="alert" class="erreur" hidden>
Saisissez une adresse email valide (ex. : nom@exemple.fr).
</p>
</div>
<button type="submit">Envoyer</button>
</form>
Validation et gestion des erreurs :
form.addEventListener('submit', (e) => {
e.preventDefault();
const erreurs = [];
// Valider chaque champ
const nom = document.getElementById('nom');
if (!nom.value.trim()) {
marquerErreur(nom, 'erreur-nom', 'Le nom est obligatoire.');
erreurs.push('Nom : obligatoire');
} else {
effacerErreur(nom, 'erreur-nom');
}
if (erreurs.length > 0) {
// Remplir la zone d'erreurs globales (live region)
const zone = document.getElementById('erreurs-globales');
zone.innerHTML = `<p>${erreurs.length} erreur${erreurs.length > 1 ? 's' : ''} à corriger :</p>
<ul>${erreurs.map(e => `<li>${e}</li>`).join('')}</ul>`;
// Focus sur le premier champ en erreur
document.querySelector('[aria-invalid="true"]')?.focus();
}
});
function marquerErreur(input, idErreur, message) {
input.setAttribute('aria-invalid', 'true');
const msgErreur = document.getElementById(idErreur);
msgErreur.textContent = message;
msgErreur.removeAttribute('hidden');
}
function effacerErreur(input, idErreur) {
input.setAttribute('aria-invalid', 'false');
const msgErreur = document.getElementById(idErreur);
msgErreur.setAttribute('hidden', '');
msgErreur.textContent = '';
}
Ce que NVDA annonce
[Focus sur le champ Nom, vide, avant soumission]
→ "Nom, zone de saisie, requis, Votre nom de famille tel qu'il apparaît…"
[Soumission avec champ vide]
→ [live region alert] "Le nom est obligatoire."
→ [focus déplacé] "Nom, zone de saisie, invalide, requis, Votre nom de famille…, Le nom est obligatoire."
[Après correction]
→ "Nom, zone de saisie, requis, Votre nom de famille…"
Erreurs fréquentes en audit
Message d’erreur non associé au champ : le message s’affiche visuellement sous le champ mais n’est pas référencé par aria-describedby. L’utilisateur AT corrige un champ sans entendre le message d’erreur.
aria-invalid non mis à jour : reste à "false" même après erreur. Le champ n’est pas annoncé comme invalide.
Focus non déplacé sur le premier champ en erreur après soumission : l’utilisateur ne sait pas quels champs corriger.
autocomplete absent : les champs nom, prénom, email, téléphone doivent avoir autocomplete. Critère 11.13 RGAA.
Spécificité WordPress FSE
Le plugin Contact Form 7 génère des messages d’erreur mais pas aria-invalid ni aria-describedby. Les messages sont dans des spans avec classes CSS, non liés programmatiquement aux champs. WPForms et Gravity Forms ont une meilleure implémentation ARIA mais à vérifier au cas par cas. Le bloc Formulaire natif Gutenberg (WordPress 6.4+) est encore limité (préférer CF7 ou WPForms avec vérification ARIA).
Critères RGAA : 11.1 , 11.2 , 11.9 , 11.10 , 11.11 .
8. Liens et boutons avec icônes
Le cas le plus fréquent et le plus simple, et pourtant source d’erreurs systématiques.
Les quatre cas à distinguer
Cas 1 : Icône décorative dans un lien/bouton avec texte visible
<!-- L'icône ne porte pas d'information — le texte suffit -->
<a href="/contact">
<svg aria-hidden="true" focusable="false"><!-- enveloppe --></svg>
Nous contacter
</a>
→ NVDA : "Nous contacter, lien"
Cas 2 : Icône seule dans un lien/bouton
<!-- L'icône est le seul contenu — aria-label obligatoire sur le lien -->
<a href="https://facebook.com/macommune"
aria-label="Page Facebook de la commune (nouvelle fenêtre)"
target="_blank"
rel="noopener noreferrer">
<svg aria-hidden="true" focusable="false"><!-- logo Facebook --></svg>
</a>
→ NVDA : "Page Facebook de la commune (nouvelle fenêtre), lien"
Cas 3 : SVG inline porteur d’information (pas dans un lien)
<!-- Le SVG lui-même est une image informative -->
<svg role="img" aria-label="Note : 4 étoiles sur 5" viewBox="0 0 100 20">
<title>Note : 4 étoiles sur 5</title>
<!-- étoiles -->
</svg>
→ NVDA : "Note : 4 étoiles sur 5, graphique"
Cas 4 : Texte sr-only dans un bouton icône
<!-- Alternative au aria-label : texte masqué dans le DOM -->
<button type="button">
<svg aria-hidden="true" focusable="false"><!-- fermer --></svg>
<span class="sr-only">Fermer la fenêtre</span>
</button>
→ NVDA : "Fermer la fenêtre, bouton"
Avantage du cas 4 vs cas 2 : le texte sr-only est traduisible par les outils de traduction automatique (Google Translate), alors qu’aria-label ne l’est pas toujours.
Erreurs fréquentes en audit
Liens réseaux sociaux avec aria-label="Facebook" : pas d’organisation mentionnée. Si plusieurs partenaires ont leurs réseaux sur la page, les liens sont indistinguables. Toujours préciser l’organisation : "Page Facebook de la Mairie de Nom_Ville".
target="_blank" sans mention : l’ouverture dans un nouvel onglet est un changement de contexte. Le mentionner dans l’aria-label : "(nouvelle fenêtre)" ou "(s'ouvre dans un nouvel onglet)".
SVG sans focusable="false" : certains navigateurs (Edge Legacy, IE) rendent les SVG focusables par défaut. Toujours ajouter focusable="false" sur les SVG avec aria-hidden.
alt sur <img> dans un lien décrivant l’image et non la destination : <a href="/contact"><img src="icone-email.png" alt="Icône email"></a> annonce “Icône email, lien”. L’alt devrait décrire la destination : alt="Nous contacter".
Spécificité WordPress FSE
Le bloc Icônes sociales (core/social-links) génère des <a> avec aria-label basé sur le nom du réseau ("Facebook", "Instagram"). Il ne mentionne pas l’organisation ni l’ouverture dans un nouvel onglet. Corriger via un filtre PHP ou dans les options du bloc si la version le permet.
Critères RGAA : 1.1 , 1.2 , 6.1 , 6.2 .
Récapitulatif : Les vérifications rapides en audit
| Composant | Vérifier en 30 secondes |
|---|---|
| Navigation | aria-label sur <nav>, aria-current="page" sur lien actif |
| Bouton burger | aria-expanded mis à jour, focus déplacé à l’ouverture |
| Accordéon | <button> dans un titre, aria-expanded sur le bouton |
| Onglets | Flèches entre onglets, aria-selected sur tous les tabs |
| Modale | Focus piégé, déplacé à l’ouverture, restauré à la fermeture |
| Carrousel | Bouton pause, alt sur les images, pas d’aria-live="assertive" |
| Formulaire | aria-describedby pointe vers le message d’erreur, aria-invalid mis à jour |
| Liens icônes | aria-label avec organisation + (nouvelle fenêtre) si target="_blank" |