Critères de succès WCAG · Level A
WCAG 4.1.1 : Analyse syntaxique (obsolète dans WCAG 2.2)
La règle WCAG 4.1.1 Parsing exige que le contenu web soit exempt d’erreurs HTML/XML majeures — comme des IDs dupliqués — qui pourraient amener les technologies d’assistance à mal interpréter la page ou à ne pas pouvoir la traiter. Bien que dépréciée dans WCAG 2.2, les règles sous-jacentes d’axe-core restent actives et les violations indiquent toujours un risque réel en matière d’accessibilité.
Ce que signifie cette règle
WCAG 4.1.1 Parsing a été initialement conçu pour garantir que les agents utilisateurs, y compris les navigateurs et les technologies d’assistance, puissent analyser et interpréter correctement le contenu web. Le critère exigeait que les pages rédigées dans des langages de balisage tels que HTML ou XML satisfassent quatre conditions structurelles : les éléments doivent avoir des balises de début et de fin complètes ; les éléments doivent être imbriqués conformément à leurs spécifications ; les éléments ne doivent pas contenir d’attributs dupliqués ; et tous les ID utilisés dans le contenu doivent être uniques.
Dans WCAG 2.2, le W3C a officiellement déprécié ce critère. La raison en est que les navigateurs modernes sont devenus très résistants au HTML mal formé, corrigeant automatiquement la plupart des erreurs structurelles avant qu’elles n’atteignent l’arbre d’accessibilité. En conséquence, bon nombre des préoccupations initiales — telles que les balises non fermées ou les éléments mal imbriqués — ne causent plus de dommages pratiques aux technologies d’assistance dans les environnements contemporains.
Cependant, la dépréciation ne signifie pas que les préoccupations du critère ont complètement disparu. Le W3C note explicitement que les attributs d’ID dupliqués restent un problème d’accessibilité significatif. Lorsque deux éléments ou plus partagent la même valeur d’id, les navigateurs doivent prendre une décision arbitraire quant à l’élément à associer aux références ARIA, aux associations de libellés ou aux liens de fragments. Cette ambiguïté peut amener les lecteurs d’écran à annoncer un contenu incorrect, à ignorer des contrôles interactifs ou à ne pas exposer du tout les libellés de formulaire. La condition de réussite du critère est donc mieux comprise aujourd’hui comme : aucune valeur d’ID dupliquée n’apparaît dans le DOM. Une page échoue à ce critère lorsque des ID sont dupliqués d’une manière qui rompt les associations programmatiques sur lesquelles les technologies d’assistance s’appuient.
Les exceptions officielles dans la spécification WCAG sont minimales. Le critère s’applique au contenu rédigé dans des langages de balisage ; il ne s’applique pas au contenu généré par des environnements de script où l’auteur n’a aucun contrôle direct sur le format de sortie. En pratique, cependant, les développeurs sont responsables du DOM final rendu, quel que soit le stack technologique utilisé pour le produire.
Pourquoi c’est important
Les ID dupliqués peuvent sembler être un problème mineur de ménage, mais leurs conséquences pour les utilisateurs de technologies d’assistance peuvent être graves. Les lecteurs d’écran tels que JAWS, NVDA et VoiceOver s’appuient sur l’arbre d’accessibilité du navigateur, qui dépend à son tour de références d’ID correctement résolues pour construire les relations entre les éléments d’interface. Lorsqu’un ID est dupliqué, le navigateur résout généralement les références uniquement vers le premier élément correspondant dans l’ordre du document, en ignorant silencieusement les éléments suivants ayant le même ID.
Pour les personnes aveugles ou malvoyantes, cela peut signifier qu’un champ de formulaire est annoncé sans son libellé, ou qu’un message d’erreur associé à un champ via aria-describedby n’est jamais lu à voix haute. Considérez un formulaire de paiement sur un site d’e-commerce où les champs d’adresse de livraison et les champs d’adresse de facturation utilisent tous des ID comme city, zip et state. Un utilisateur de lecteur d’écran remplissant la section de facturation peut entendre le libellé de la section de livraison à la place, ce qui entraîne confusion, erreurs et abandon potentiel de la transaction.
Pour les personnes ayant des handicaps cognitifs, des associations de libellés rompues signifient que le texte visible qu’elles lisent à l’écran ne correspond pas à ce que leur lecteur d’écran ou leur logiciel de commande vocale annonce, créant une dissonance désorientante qui augmente la charge cognitive.
Pour les personnes ayant un handicap moteur qui s’appuient sur des logiciels de saisie vocale tels que Dragon NaturallySpeaking, les ID dupliqués peuvent amener les commandes vocales visant un contrôle spécifique à activer le mauvais élément, car le logiciel peut s’appuyer en interne sur un ciblage basé sur les ID.
Au-delà de l’impact sur le handicap, les ID dupliqués affectent également le SEO : les robots d’indexation des moteurs de recherche qui s’appuient sur des identifiants de fragments pour indexer des sections spécifiques de page peuvent indexer un contenu incorrect lorsque les ID ne sont pas uniques. L’ergonomie est également dégradée pour tous les utilisateurs lorsque les liens d’ancrage internes naviguent vers le mauvais emplacement sur la page.
Environ 2,2 milliards de personnes dans le monde ont une forme de déficience visuelle selon l’Organisation mondiale de la santé. Une proportion significative de ces utilisateurs s’appuie sur des lecteurs d’écran directement impactés par des associations d’ID rompues. Garantir l’unicité des ID est l’une des corrections les moins coûteuses et les plus impactantes qu’une équipe de développement puisse mettre en œuvre.
Règles axe-core associées
Trois règles axe-core correspondent directement aux préoccupations soulevées par WCAG 4.1.1. Chacune cible une manifestation spécifique du problème d’ID dupliqué :
- duplicate-id : Cette règle vérifie l’ensemble du DOM pour tout attribut
iddont la valeur apparaît sur plus d’un élément. Elle signale tous les éléments au-delà du premier qui partagent un ID, que ces éléments soient interactifs ou référencés par ARIA ou non. C’est la plus large des trois règles et elle détecte les violations structurelles même lorsqu’aucune relation ARIA explicite n’est impliquée. Un déclencheur courant est l’utilisation de frameworks basés sur des composants qui rendent le même composant réutilisable plusieurs fois sur une page sans générer d’ID uniques pour chaque instance. - duplicate-id-active : Cette règle restreint son focus aux ID dupliqués sur les éléments interactifs ou focalisables — boutons, liens, champs de saisie et tout élément avec un
tabindexnon négatif. L’impact sur l’accessibilité est plus élevé ici car les technologies d’assistance et la navigation au clavier dépendent toutes deux de la capacité à identifier sans ambiguïté un contrôle actif. Lorsqu’un bouton de soumission et une icône sans rapport partagent le même ID, l’ordre de tabulation annoncé et la gestion programmatique du focus peuvent tous deux être rompus. - duplicate-id-aria : C’est la plus critique des trois règles. Elle signale les ID dupliqués spécifiquement lorsque ces ID sont référencés par des attributs ARIA —
aria-labelledby,aria-describedby,aria-controls,aria-ownset d’autres attributs de relation similaires. Étant donné que ces attributs sont le mécanisme principal par lequel les technologies d’assistance comprennent les relations entre les éléments, les duplications ici rompent directement le calcul du nom accessible et les relations de rôle. Un exemple d’échec serait deux éléments<div>avecid='dialog-title'lorsqu’une modale utilisearia-labelledby='dialog-title'— le lecteur d’écran annoncera l’élément qui apparaît en premier dans le DOM, qui peut ne pas être l’en-tête de dialogue prévu.
Les outils automatisés sont bien adaptés pour détecter les ID dupliqués car la vérification est purement syntaxique : l’outil lit le DOM et compare les valeurs d’ID. Aucun test manuel n’est strictement requis pour ce critère. Cependant, si des ID sont générés dynamiquement après une interaction utilisateur — par exemple, un défilement infini qui injecte un nouveau contenu avec des ID répétés — les analyses automatisées exécutées au chargement de la page peuvent manquer des violations qui n’apparaissent que plus tard. Dans de tels cas, les testeurs doivent déclencher le comportement dynamique avant d’exécuter les analyses, ou surveiller le DOM à l’aide des outils de développement du navigateur après les interactions.
Comment tester
- Analyse automatisée avec axe DevTools : Ouvrez la page dans Chrome ou Firefox. Ouvrez DevTools (F12), accédez au panneau axe DevTools (ou installez l’extension de navigateur) et lancez une analyse de page complète. Filtrez les résultats pour les règles duplicate-id, duplicate-id-active et duplicate-id-aria. Chaque violation listera les éléments concernés et leurs valeurs d’ID dupliquées. Exportez le rapport si nécessaire pour la documentation d’audit. Pour Lighthouse, exécutez un audit d’accessibilité Lighthouse depuis l’onglet Lighthouse des DevTools et recherchez l’audit « Document has multiple elements with the same id ».
- Vérification via la console des outils de développement du navigateur : Ouvrez la console du navigateur et exécutez l’extrait JavaScript suivant pour trouver tous les ID dupliqués sur la page actuelle :
const ids = [...document.querySelectorAll('[id]')].map(el => el.id); const dupes = ids.filter((id, i) => ids.indexOf(id) !== i); console.log([...new Set(dupes)]);Cela affichera un tableau de toutes les valeurs d’ID qui apparaissent plus d’une fois. Un tableau vide signifie qu’aucun doublon n’est présent. - Tests avec lecteur d’écran NVDA et Firefox : Chargez la page avec NVDA en cours d’exécution. Naviguez vers un formulaire contenant des champs avec des libellés associés via
for/idouaria-labelledby. Parcourez chaque champ avec la touche Tab et écoutez attentivement si NVDA annonce le libellé correct. Si un champ est annoncé sans libellé, ou avec le mauvais libellé provenant d’une autre section, un ID dupliqué peut en être la cause. Répétez ce processus pour toutes les régions repères ARIA, les boîtes de dialogue modales ou les widgets qui utilisentaria-controlsouaria-describedby. - VoiceOver et Safari sur macOS : Activez VoiceOver (Commande+F5). Utilisez le rotor VoiceOver (Contrôle+Option+U) pour ouvrir la liste des contrôles de formulaire ou des liens et vérifiez que chaque contrôle possède un libellé unique et correctement annoncé. Naviguez dans toute boîte de dialogue modale et confirmez que le titre de la boîte de dialogue est correctement annoncé lorsque la boîte de dialogue s’ouvre.
- JAWS et Chrome : Avec JAWS en cours d’exécution, ouvrez la page et utilisez la liste des champs de formulaire de JAWS (Insert+F5) pour passer en revue tous les éléments de formulaire et leurs libellés associés. Vérifiez qu’aucun des champs ne partage le même texte de libellé lorsqu’ils devraient être distincts.
- Tests de contenu dynamique : Si la page utilise le défilement infini, la navigation monopage ou des boîtes de dialogue modales injectées via JavaScript, interagissez avec ces fonctionnalités pour charger un nouveau contenu dans le DOM, puis relancez l’analyse automatisée ou l’extrait de console pour vérifier l’absence de doublons introduits par le contenu dynamique.
Comment corriger
ID de champs de formulaire dupliqués dans des sections répétées — Incorrect
<!-- Shipping Address -->
<label for='city'>City</label>
<input type='text' id='city' name='shipping-city'>
<!-- Billing Address -->
<label for='city'>City</label>
<input type='text' id='city' name='billing-city'>
<!-- FAIL: Both inputs share id='city'. The second label's 'for' attribute
resolves to the first input, so screen readers announce the wrong field. -->
ID de champs de formulaire dupliqués dans des sections répétées — Correct
<!-- Shipping Address -->
<label for='shipping-city'>City</label>
<input type='text' id='shipping-city' name='shipping-city'>
<!-- Billing Address -->
<label for='billing-city'>City</label>
<input type='text' id='billing-city' name='billing-city'>
<!-- PASS: Each input has a unique ID scoped to its section.
Screen readers correctly announce each field's label. -->
Composant réutilisable rendu plusieurs fois — Incorrect
<!-- Product Card 1 -->
<div class='product-card'>
<img id='product-img' src='shoe.jpg' alt='Running Shoe'>
<button id='add-to-cart' aria-describedby='product-desc'>Add to Cart</button>
<p id='product-desc'>Free shipping on orders over 500 TL.</p>
</div>
<!-- Product Card 2 (same template, duplicate IDs) -->
<div class='product-card'>
<img id='product-img' src='boot.jpg' alt='Hiking Boot'>
<button id='add-to-cart' aria-describedby='product-desc'>Add to Cart</button>
<p id='product-desc'>Free shipping on orders over 500 TL.</p>
</div>
<!-- FAIL: IDs duplicated across cards. aria-describedby on the second button
resolves to the <p> in the first card, not the second. -->
Composant réutilisable rendu plusieurs fois — Correct
<!-- Product Card 1 -->
<div class='product-card'>
<img id='product-img-1' src='shoe.jpg' alt='Running Shoe'>
<button id='add-to-cart-1' aria-describedby='product-desc-1'>Add to Cart</button>
<p id='product-desc-1'>Free shipping on orders over 500 TL.</p>
</div>
<!-- Product Card 2 -->
<div class='product-card'>
<img id='product-img-2' src='boot.jpg' alt='Hiking Boot'>
<button id='add-to-cart-2' aria-describedby='product-desc-2'>Add to Cart</button>
<p id='product-desc-2'>Free shipping on orders over 500 TL.</p>
</div>
<!-- PASS: Each card's IDs are unique. ARIA references resolve correctly
within their own card. Use a counter, UUID, or slug-based strategy
to generate IDs in your component framework. -->
Boîte de dialogue modale avec référence d’étiquette ARIA dupliquée — Incorrect
<!-- A generic heading used as a reusable ID -->
<h1 id='dialog-title'>Welcome</h1>
<div role='dialog' aria-modal='true' aria-labelledby='dialog-title'>
<h2 id='dialog-title'>Confirm Your Order</h2>
<p>Are you sure you want to place this order?</p>
<button>Confirm</button>
<button>Cancel</button>
</div>
<!-- FAIL: Two elements share id='dialog-title'. The dialog's
aria-labelledby resolves to the page <h1>, not the dialog heading.
Screen readers will announce 'Welcome' as the dialog name. -->
Boîte de dialogue modale avec référence d’étiquette ARIA dupliquée — Correct
<h1>Welcome</h1>
<div role='dialog' aria-modal='true' aria-labelledby='confirm-dialog-title'>
<h2 id='confirm-dialog-title'>Confirm Your Order</h2>
<p>Are you sure you want to place this order?</p>
<button>Confirm</button>
<button>Cancel</button>
</div>
<!-- PASS: The dialog heading has a unique, descriptive ID.
aria-labelledby correctly identifies the dialog to screen readers
as 'Confirm Your Order'. -->
Erreurs courantes
- Copier-coller le balisage d’un composant sans mettre à jour les ID : Les développeurs dupliquent souvent une section HTML fonctionnelle pour une deuxième instance (un deuxième bloc d’adresse, un deuxième panneau d’onglet, un deuxième élément d’accordéon) et oublient de mettre à jour toutes les valeurs d’ID pour qu’elles soient uniques. Établissez une convention de nommage telle que
component-name-index(par exemple,accordion-panel-1,accordion-panel-2) et appliquez-la lors des revues de code. - Utiliser des ID statiques dans des composants de framework sans stratégie de clé unique : React, Vue, Angular et des frameworks similaires peuvent rendre le même composant des dizaines de fois sur une page. Utiliser un
id='search-input'codé en dur à l’intérieur d’un composant réutilisable créera autant de doublons qu’il y a d’instances. Dérivez toujours les ID à partir des props, d’un compteur ou d’un utilitaire commeuseId()dans React 18+. - S’appuyer sur le ciblage par classe CSS au lieu de corriger le HTML : Certains développeurs contournent les problèmes d’ID dupliqués en remplaçant les sélecteurs JavaScript
getElementByIdparquerySelectoravec une classe, tout en laissant les ID dupliqués en place. Cela peut corriger le comportement visuel mais ne fait rien pour résoudre les associations rompues dans l’arbre d’accessibilité. - Boucles de templating côté serveur qui génèrent le même ID à chaque itération : Un template Jinja2, Blade ou Twig qui rend
id='item-title'à l’intérieur d’une boucle{% for item in items %}produira un doublon pour chaque élément de la liste. Ajoutez toujours l’index de boucle ou l’identifiant de l’élément à l’ID :id='item-title-{{ loop.index }}'. - Ignorer les ID dans les éléments masqués ou hors écran : Les éléments avec
display: noneouvisibility: hiddensont toujours présents dans le DOM et leurs ID sont toujours enregistrés. Un modèle de modale masquée qui partage un ID avec un élément visible provoquera les mêmes échecs d’analyse. Utilisez l’attributhiddenou assurez-vous que les modèles masqués utilisent des ID uniques. - Supposer que le fait de se limiter à un Shadow DOM résout le problème : Les ID à l’intérieur d’un Shadow DOM natif sont limités à ce contexte et n’entrent pas en conflit avec les ID du light DOM ou d’autres racines shadow. Cependant, de nombreuses bibliothèques de composants utilisent un polyfill ou une approche non standard qui ne fournit pas un véritable cloisonnement. Vérifiez la sortie DOM réelle plutôt que de supposer le comportement du framework.
- Générer des ID à partir de contenu fourni par l’utilisateur sans nettoyage ni déduplication : Créer des ID à partir de noms de produits, de titres d’articles ou d’autres textes dynamiques peut produire des collisions lorsque deux éléments partagent le même nom (par exemple, deux produits appelés « Classic » générant tous deux
id='classic'). Ajoutez toujours une clé de base de données unique ou un index aux ID dérivés du contenu. - Ne pas tester après la navigation côté client dans les applications monopage : Les SPA qui injectent un nouveau contenu de route dans le DOM sans rechargement complet de la page peuvent accumuler des ID provenant de routes précédemment visitées si l’ancien contenu n’est pas correctement démonté. Exécutez des analyses axe après avoir navigué entre les routes, et pas seulement au chargement initial.
- Oublier les ID générés par les éléments
<defs>et<use>SVG : Les sprites SVG qui définissent des symboles avec des ID à l’intérieur de<defs>puis les référencent avec<use href='#icon-arrow'>peuvent créer des ID dupliqués si la même définition de symbole est incluse plusieurs fois sur une page. Centralisez les définitions de sprites SVG et incluez-les une seule fois. - Passer sous silence les ID générés par des widgets tiers, des plugins de chat ou des scripts d’analytique : Les scripts tiers injectent parfois des éléments avec des ID codés en dur. Si votre propre code utilise le même ID, un conflit apparaît que vous ne remarquerez peut-être pas pendant le développement. Auditez le DOM rendu complet, y compris le contenu tiers, et signalez les conflits aux fournisseurs ou espacez les noms de vos propres ID pour éviter les collisions.
Lien avec la réglementation turque en matière d’accessibilité
La Circulaire présidentielle 2025/10 de la Turquie, publiée au Journal officiel n° 32933 le 21 juin 2025, établit des exigences obligatoires en matière d’accessibilité web pour un large ensemble d’entités publiques et privées opérant en Turquie. La circulaire adopte WCAG 2.2 comme norme de référence technique, faisant de la conformité de niveau A le minimum légal pour toutes les entités concernées.
WCAG 4.1.1 Parsing est un critère de niveau A. Même si le W3C l’a déprécié dans WCAG 2.2, les règles axe-core qui appliquent sa préoccupation principale — l’unicité des ID — restent actives et continuent d’être signalées dans les audits d’accessibilité menés selon WCAG 2.2. Les audits réglementaires turcs et les revues de conformité qui utilisent des outils d’analyse automatisés signaleront donc les violations duplicate-id comme des échecs potentiels de niveau A, indépendamment du statut déprécié du critère au niveau de la spécification. Les organisations cherchant à démontrer leur conformité doivent traiter les violations d’ID dupliqués comme des problèmes bloquants.
Les entités couvertes par la Circulaire présidentielle 2025/10 incluent un large éventail d’institutions publiques et d’organisations du secteur privé : tous les organismes gouvernementaux centraux et locaux et leurs agences affiliées ; les banques et institutions financières réglementées par la législation bancaire turque ; les hôpitaux et prestataires de soins de santé privés ; les opérateurs de télécommunications desservant 200 000 abonnés ou plus ; les plateformes d’e-commerce et les places de marché en ligne ; les agences de voyage et les tour-opérateurs ; les entreprises de transport privées opérant dans le cadre de concessions publiques ; et les écoles et établissements d’enseignement privés autorisés par le ministère de l’Éducation nationale (MoNE).
La circulaire établit un calendrier de conformité progressif. Les institutions publiques doivent atteindre une conformité complète de niveau A dans un délai d’un an à compter de la date de publication de la circulaire. Les entités du secteur privé dans les catégories couvertes disposent de deux ans pour atteindre le même niveau. Le non-respect expose les entités concernées à un examen réglementaire, à d’éventuelles sanctions administratives et à un risque de réputation sur un marché de plus en plus sensibilisé à l’accessibilité.
Pour les organisations turques, traiter les violations d’ID dupliqués est particulièrement pertinent dans les contextes où des formulaires numériques, des flux de paiement en ligne, des portails de services gouvernementaux et des systèmes de prise de rendez-vous de santé sont impliqués. Ce sont précisément les types d’interface les plus susceptibles d’utiliser des sections de formulaire répétées, des composants réutilisables et des intégrations de widgets tiers qui introduisent des ID dupliqués. Mettre en place des tests d’accessibilité automatisés — par exemple en intégrant axe-core dans les pipelines CI/CD — dans le cadre du processus de développement est à la fois une bonne pratique technique et une stratégie pragmatique pour maintenir une conformité réglementaire continue au regard des exigences de la circulaire.
