Critérios de Sucesso WCAG · Level A

WCAG 4.1.1: Análise sintática (Obsoleto no WCAG 2.2)

A diretriz WCAG 4.1.1 Parsing exige que o conteúdo da web esteja livre de erros graves de HTML/XML — como IDs duplicados — que possam levar as tecnologias assistivas a interpretar incorretamente a página ou não conseguir processá-la. Embora esteja obsoleta na WCAG 2.2, as regras subjacentes do axe-core continuam ativas e as violações ainda indicam um risco real de acessibilidade.

O que Esta Regra Significa

O WCAG 4.1.1 Parsing foi originalmente criado para garantir que os agentes de usuário, incluindo navegadores e tecnologias assistivas, pudessem analisar e interpretar o conteúdo da web com precisão. O critério exigia que páginas escritas em linguagens de marcação como HTML ou XML atendessem a quatro condições estruturais: elementos devem ter tags de abertura e fechamento completas; elementos devem ser aninhados de acordo com suas especificações; elementos não devem conter atributos duplicados; e quaisquer IDs usados no conteúdo devem ser únicos.

No WCAG 2.2, o W3C descontinuou formalmente esse critério. A justificativa foi que os navegadores modernos se tornaram altamente resilientes a HTML malformado, corrigindo automaticamente a maioria dos erros estruturais antes mesmo que cheguem à árvore de acessibilidade. Como resultado, muitas das preocupações originais — como tags não fechadas ou elementos aninhados incorretamente — deixaram de causar danos práticos às tecnologias assistivas em ambientes contemporâneos.

No entanto, a descontinuação não significa que as preocupações do critério tenham desaparecido completamente. O W3C observa explicitamente que atributos ID duplicados continuam sendo um problema de acessibilidade significativo. Quando dois ou mais elementos compartilham o mesmo valor de id, os navegadores precisam tomar uma decisão arbitrária sobre qual elemento associar a referências ARIA, associações de rótulos ou links de fragmento. Essa ambiguidade pode fazer com que leitores de tela anunciem conteúdo incorreto, ignorem controles interativos ou deixem de expor rótulos de formulários por completo. A condição de aprovação do critério é, portanto, melhor compreendida hoje como: nenhum valor de ID duplicado aparece no DOM. Uma página falha nesse critério quando IDs são duplicados de maneiras que quebram associações programáticas das quais as tecnologias assistivas dependem.

As exceções oficiais na especificação WCAG são mínimas. O critério se aplica a conteúdo escrito em linguagens de marcação; ele não se aplica a conteúdo gerado por ambientes de script em que o autor não tem controle direto sobre o formato de saída. Na prática, porém, desenvolvedores são responsáveis pelo DOM final renderizado, independentemente da stack de tecnologia usada para produzi-lo.

Por Que Isso Importa

IDs duplicados podem parecer um problema menor de organização, mas suas consequências para usuários de tecnologia assistiva podem ser graves. Leitores de tela como JAWS, NVDA e VoiceOver dependem da árvore de acessibilidade do navegador, que por sua vez depende de referências de ID resolvidas corretamente para construir as relações entre elementos da interface. Quando um ID é duplicado, o navegador normalmente resolve referências apenas para o primeiro elemento correspondente na ordem do documento, ignorando silenciosamente elementos subsequentes com o mesmo ID.

Para pessoas cegas e com baixa visão, isso pode significar que um campo de formulário é anunciado sem seu rótulo, ou que uma mensagem de erro associada a um input via aria-describedby nunca seja lida em voz alta. Considere um formulário de checkout em um site de e-commerce em que os campos de endereço de entrega e de endereço de cobrança usam IDs como city, zip e state. Uma pessoa usuária de leitor de tela preenchendo a seção de cobrança pode ouvir o rótulo da seção de entrega em vez disso, levando a confusão, erros e possível abandono da transação.

Para pessoas com deficiências cognitivas, associações de rótulo quebradas significam que o texto visível que elas leem na tela não corresponde ao que seu leitor de tela ou software de controle por voz anuncia, criando uma desconexão desorientadora que aumenta a carga cognitiva.

Para pessoas com deficiência motora que dependem de software de entrada por voz como Dragon NaturallySpeaking, IDs duplicados podem fazer com que comandos de voz direcionados a um controle específico ativem o elemento errado, porque o software pode depender de direcionamento baseado em ID internamente.

Além do impacto na deficiência, IDs duplicados também afetam o SEO: rastreadores de mecanismos de busca que dependem de identificadores de fragmento para indexar seções específicas da página podem indexar conteúdo incorreto quando os IDs não são únicos. A usabilidade também é prejudicada para todas as pessoas usuárias quando links âncora na página navegam para o local errado na página.

Aproximadamente 2,2 bilhões de pessoas no mundo têm algum tipo de deficiência visual, de acordo com a Organização Mundial da Saúde. Uma proporção significativa dessas pessoas depende de leitores de tela que são diretamente impactados por associações de ID quebradas. Garantir IDs únicos é uma das correções de menor esforço e maior impacto que uma equipe de desenvolvimento pode implementar.

Regras Relacionadas do Axe-core

Três regras do axe-core mapeiam diretamente para as preocupações levantadas pelo WCAG 4.1.1. Cada uma aborda uma manifestação específica do problema de ID duplicado:

  • duplicate-id: Esta regra verifica todo o DOM em busca de qualquer valor de atributo id que apareça em mais de um elemento. Ela sinaliza todos os elementos além do primeiro que compartilham um ID, independentemente de esses elementos serem interativos ou referenciados por ARIA. Esta é a mais ampla das três regras e captura violações estruturais mesmo quando nenhuma relação ARIA explícita está envolvida. Um gatilho comum são frameworks baseados em componentes que renderizam o mesmo componente reutilizável várias vezes em uma página sem gerar IDs únicos para cada instância.
  • duplicate-id-active: Esta regra restringe seu foco a IDs duplicados em elementos que são interativos ou focáveis — botões, links, inputs e qualquer elemento com um tabindex não negativo. O impacto na acessibilidade é maior aqui porque tecnologias assistivas e navegação por teclado dependem da capacidade de identificar de forma inequívoca um controle ativo. Quando um botão de envio e um ícone não relacionado compartilham o mesmo ID, anúncios da ordem de tabulação e o gerenciamento programático de foco podem falhar.
  • duplicate-id-aria: Esta é a mais crítica das três regras. Ela sinaliza IDs duplicados especificamente quando esses IDs são referenciados por atributos ARIA — aria-labelledby, aria-describedby, aria-controls, aria-owns e atributos de relacionamento semelhantes. Como esses atributos são o principal mecanismo pelo qual as tecnologias assistivas entendem as relações entre elementos, duplicatas aqui quebram diretamente o cálculo do nome acessível e as relações de função. Um exemplo de falha seria dois elementos <div> com id='dialog-title' quando um modal usa aria-labelledby='dialog-title' — o leitor de tela anunciará o elemento que aparecer primeiro no DOM, que pode não ser o cabeçalho de diálogo pretendido.

Ferramentas automatizadas são bem adequadas para detectar IDs duplicados porque a verificação é puramente sintática: a ferramenta lê o DOM e compara valores de ID. Nenhum teste manual é estritamente necessário para esse critério. No entanto, se IDs forem gerados dinamicamente após a interação da pessoa usuária — por exemplo, um scroll infinito que injeta novo conteúdo com IDs repetidos — varreduras automatizadas executadas no carregamento da página podem não detectar violações que só aparecem depois. Nesses casos, testadores devem acionar o comportamento dinâmico antes de executar as varreduras ou monitorar o DOM usando as ferramentas de desenvolvedor do navegador após as interações.

Como Testar

  1. Varredura automatizada com axe DevTools: Abra a página no Chrome ou Firefox. Abra o DevTools (F12), navegue até o painel do axe DevTools (ou instale a extensão do navegador) e execute uma varredura de página inteira. Filtre os resultados pelas regras duplicate-id, duplicate-id-active e duplicate-id-aria. Cada violação listará os elementos afetados e seus valores de ID duplicados. Exporte o relatório se necessário para documentação de auditoria. Para o Lighthouse, execute uma auditoria de acessibilidade do Lighthouse na aba Lighthouse do DevTools e procure pela auditoria "Document has multiple elements with the same id".
  2. Verificação pelo console do DevTools do navegador: Abra o console do navegador e execute o seguinte trecho de JavaScript para encontrar todos os IDs duplicados na página atual: const ids = [...document.querySelectorAll('[id]')].map(el => el.id); const dupes = ids.filter((id, i) => ids.indexOf(id) !== i); console.log([...new Set(dupes)]); Isso imprimirá um array de todos os valores de ID que aparecem mais de uma vez. Um array vazio significa que não há duplicatas.
  3. Teste com leitor de tela usando NVDA e Firefox: Carregue a página com o NVDA em execução. Navegue até um formulário que contenha campos com rótulos associados via for/id ou aria-labelledby. Use Tab para percorrer cada campo e ouça com atenção se o NVDA anuncia o rótulo correto. Se um campo for anunciado sem rótulo ou com o rótulo errado de uma seção diferente, um ID duplicado pode ser a causa. Repita esse processo para quaisquer regiões de marco ARIA, diálogos modais ou widgets que usem aria-controls ou aria-describedby.
  4. VoiceOver e Safari no macOS: Ative o VoiceOver (Command+F5). Use o rotor do VoiceOver (Control+Option+U) para abrir a lista de Controles de Formulário ou Links e verifique se cada controle tem um rótulo exclusivo e anunciado corretamente. Navegue em qualquer diálogo modal e confirme se o título do diálogo é anunciado corretamente quando o diálogo é aberto.
  5. JAWS e Chrome: Com o JAWS em execução, abra a página e use a lista de campos de formulário do JAWS (Insert+F5) para revisar todos os elementos de formulário e seus rótulos associados. Verifique se nenhum dois campos compartilham o mesmo texto de rótulo quando deveriam ser distintos.
  6. Teste de conteúdo dinâmico: Se a página usar scroll infinito, navegação de página única ou diálogos modais injetados via JavaScript, interaja com esses recursos para carregar novo conteúdo no DOM e, em seguida, execute novamente a varredura automatizada ou o trecho de console para verificar duplicatas introduzidas pelo conteúdo dinâmico.

Como Corrigir

IDs de campos de formulário duplicados em seções repetidas — Incorreto

<!-- 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. -->

IDs de campos de formulário duplicados em seções repetidas — Correto

<!-- 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. -->

Componente reutilizável renderizado várias vezes — Incorreto

<!-- 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. -->

Componente reutilizável renderizado várias vezes — Correto

<!-- 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. -->

Diálogo modal com referência de rótulo ARIA duplicada — Incorreto

<!-- 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. -->

Diálogo modal com referência de rótulo ARIA duplicada — Correto

<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'. -->

Erros Comuns

  • Copiar e colar marcação de componente sem atualizar IDs: Desenvolvedores frequentemente duplicam uma seção de HTML que funciona para uma segunda instância (um segundo bloco de endereço, um segundo painel de aba, um segundo item de acordeão) e esquecem de atualizar todos os valores de ID para serem únicos. Estabeleça uma convenção de nomenclatura como component-name-index (por exemplo, accordion-panel-1, accordion-panel-2) e aplique-a na revisão de código.
  • Usar IDs estáticos em componentes de framework sem uma estratégia de chave única: React, Vue, Angular e frameworks semelhantes podem renderizar o mesmo componente dezenas de vezes em uma página. Usar um id='search-input' fixo dentro de um componente reutilizável criará tantas duplicatas quanto houver instâncias. Sempre derive IDs de props, de um contador ou de um utilitário como useId() no React 18+.
  • Confiar em targeting por classe CSS em vez de corrigir o HTML: Alguns desenvolvedores contornam problemas de ID duplicado trocando seletores JavaScript de getElementById para querySelector com uma classe, deixando os IDs duplicados no lugar. Isso pode corrigir o comportamento visual, mas não resolve as associações da árvore de acessibilidade que estão quebradas.
  • Loops de template no servidor que geram o mesmo ID em cada iteração: Um template Jinja2, Blade ou Twig que renderiza id='item-title' dentro de um loop {% for item in items %} produzirá uma duplicata para cada item na lista. Sempre acrescente o índice do loop ou o identificador do item ao ID: id='item-title-{{ loop.index }}'.
  • Ignorar IDs em elementos ocultos ou fora da tela: Elementos com display: none ou visibility: hidden ainda estão presentes no DOM e seus IDs ainda são registrados. Um template de modal oculto que compartilha um ID com um elemento visível causará as mesmas falhas de parsing. Use o atributo hidden ou garanta que templates ocultos usem IDs únicos.
  • Presumir que o escopo em um Shadow DOM resolve o problema: IDs dentro de Shadow DOM nativo são escopados e não entram em conflito com IDs no light DOM ou em outras raízes shadow. No entanto, muitas bibliotecas de componentes usam um polyfill ou abordagem não padrão que não fornece escopo verdadeiro. Verifique a saída real do DOM em vez de presumir o comportamento do framework.
  • Gerar IDs com base em conteúdo fornecido pela pessoa usuária sem sanitização ou deduplicação: Criar IDs a partir de nomes de produtos, títulos de artigos ou outro texto dinâmico pode produzir colisões quando dois itens compartilham o mesmo nome (por exemplo, dois produtos chamados "Classic" gerando ambos id='classic'). Sempre acrescente uma chave de banco de dados única ou índice a IDs derivados de conteúdo.
  • Não testar após navegação no lado do cliente em aplicações de página única: SPAs que injetam novo conteúdo de rota no DOM sem recarregar a página podem acumular IDs de rotas visitadas anteriormente se o conteúdo antigo não for desmontado corretamente. Execute varreduras do axe após navegar entre rotas, não apenas no carregamento inicial.
  • Esquecer IDs gerados em elementos SVG <defs> e <use>: Padrões de sprite SVG que definem símbolos com IDs dentro de <defs> e depois os referenciam com <use href='#icon-arrow'> podem criar IDs duplicados se a mesma definição de símbolo for incluída várias vezes em uma página. Centralize as definições de sprite SVG e inclua-as apenas uma vez.
  • Ignorar IDs gerados por widgets de terceiros, plugins de chat ou scripts de analytics: Scripts de terceiros às vezes injetam elementos com IDs fixos. Se o seu próprio código usar o mesmo ID, surge um conflito que você pode não perceber durante o desenvolvimento. Audite o DOM renderizado completo, incluindo conteúdo de terceiros, e reporte conflitos a fornecedores ou use namespaces em seus próprios IDs para evitar colisões.

Relação com as Regulamentações de Acessibilidade da Turquia

A Circular Presidencial 2025/10 da Turquia, publicada no Diário Oficial de número 32933 em 21 de junho de 2025, estabelece requisitos obrigatórios de acessibilidade na web para um amplo conjunto de entidades públicas e privadas que operam na Turquia. A circular adota o WCAG 2.2 como seu padrão técnico de referência, tornando a conformidade de Nível A a linha de base legal mínima para todas as entidades abrangidas.

O WCAG 4.1.1 Parsing é um critério de Nível A. Embora o W3C o tenha descontinuado no WCAG 2.2, as regras do axe-core que aplicam sua principal preocupação — IDs únicos — permanecem ativas e continuam a ser sinalizadas em auditorias de acessibilidade conduzidas com base no WCAG 2.2. Auditorias regulatórias turcas e revisões de conformidade que usam ferramentas de varredura automatizada, portanto, sinalizarão violações de duplicate-id como possíveis falhas de Nível A, independentemente do status descontinuado do critério no nível da especificação. Organizações que buscam demonstrar conformidade devem tratar violações de ID duplicado como questões bloqueadoras.

As entidades abrangidas pela Circular Presidencial 2025/10 incluem uma ampla gama de instituições públicas e organizações do setor privado: todos os órgãos de governo central e local e suas agências vinculadas; bancos e instituições financeiras reguladas pela legislação bancária turca; hospitais e prestadores de serviços de saúde privados; operadoras de telecomunicações que atendem 200.000 ou mais assinantes; plataformas de e-commerce e marketplaces online; agências de viagem e operadoras de turismo; empresas de transporte privado que operam sob concessões públicas; e escolas e instituições de ensino privadas autorizadas pelo Ministério da Educação Nacional (MoNE).

A circular estabelece um cronograma de conformidade em fases. Instituições públicas devem alcançar conformidade total de Nível A em até um ano a partir da data de publicação da circular. Entidades do setor privado nas categorias abrangidas têm dois anos para atingir o mesmo padrão. A falta de conformidade expõe as entidades abrangidas a escrutínio regulatório, possíveis sanções administrativas e risco reputacional em um mercado cada vez mais atento à acessibilidade.

Para organizações turcas, tratar violações de ID duplicado é particularmente relevante em contextos em que formulários digitais, fluxos de pagamento online, portais de serviços governamentais e sistemas de agendamento de saúde estão envolvidos. Esses são precisamente os tipos de interface mais propensos a usar seções de formulário repetidas, componentes reutilizáveis e integrações de widgets de terceiros que introduzem IDs duplicados. Estabelecer testes automatizados de acessibilidade — como integrar o axe-core em pipelines de CI/CD — como parte do processo de desenvolvimento é tanto uma boa prática técnica quanto uma estratégia pragmática para manter a conformidade regulatória contínua sob os requisitos da circular.