Um revisor encontrou três critérios WCAG errados no meu plugin de acessibilidade. Fui verificar e encontrei oito.

Eu desenvolvo um scanner de acessibilidade para WordPress. Na semana passada o revisor de um marketplace rejeitou-o, e entre os motivos estava este:

As regras de conformidade precisam de correção. «Idioma dos trechos» apenas valida os atributos lang já presentes e não consegue detetar trechos em língua estrangeira não marcados; a regra do landmark principal é WCAG 1.3.6 de nível AAA mas é apresentada como uma verificação AA; e os id duplicados não deveriam ser apresentados como uma violação das WCAG 2.2 ao abrigo do 4.1.1.

Três constatações. As três corretas. O que se segue é o que aconteceu quando deixei de corrigir as três e verifiquei as outras vinte e duas.

A regra que já não existe

Começo pela terceira, porque é a mais fácil de verificar e a mais amplamente errada.

O critério de sucesso 4.1.1 Parsing foi removido das WCAG 2.2. Não foi depreciado nem suavizado: removido. A Recomendação do W3C lista-o na secção de conformidade como «Parsing (Obsolete and removed)». Saiu porque aquilo de que protegia — tecnologias de apoio que engasgavam com marcação malformada — deixou de ser um modo de falha real desde que navegadores e APIs de acessibilidade convergiram sobre como recuperar de HTML defeituoso.

O meu scanner reportava atributos id duplicados como violação das WCAG 4.1.1. Perante as WCAG 2.2, esse critério já não está lá para ser violado.

Os id duplicados continuam a merecer correção. Quebram as associações label for e as referências aria-labelledby, de modo que é anunciado o elemento errado, ou nenhum. Mas isso é um problema do 4.1.2 quando quebra efetivamente um nome acessível, e detetá-lo é uma verificação diferente de contar id duplicados. O que eu tinha era uma verificação genérica de id duplicados a usar o número de um critério retirado.

Depois verifiquei o resto

O revisor tinha encontrado três. Eu podia ter corrigido três. Em vez disso peguei nas 25 regras e verifiquei cada uma contra a Recomendação WCAG 2.2 e contra o modo como o axe-core classifica a regra equivalente — porque o axe-core é a implementação de referência sobre a qual boa parte deste setor está construída, e faz uma distinção que eu tinha perdido.

Oito regras estavam erradas.

RegraDeclaravaNa realidade
Id duplicados4.1.1Removido das WCAG 2.2
Um único landmark main1.3.6 AAA1.3.6 é Identify Purpose, um critério sem relação
Idioma dos trechos3.1.2 AA3.1.2 é nível A — e a verificação não fazia o que o título prometia
Texto de link vago2.4.4O 2.4.4 é satisfeito pelo contexto
Níveis de título saltados1.3.1As WCAG não exigem níveis sequenciais
h1 em falta1.3.1Boa prática
Título vazio1.3.1Boa prática
tabindex positivo2.4.3Boa prática

Algumas merecem uma frase.

Texto de link vago. O 2.4.4 chama-se Link Purpose (In Context). Em contexto. Um link que diz «leia mais» satisfá-lo se o parágrafo, o item de lista ou a célula que o rodeia tornarem claro o destino — o que costuma acontecer. O critério que exige que o texto do link se sustente sozinho é o 2.4.9, e é AAA. Portanto «leia mais» repetido ao longo de uma página é um problema real de usabilidade para quem percorre os links com o tabulador, e não é uma violação de nível A.

Níveis de título. Não existe critério de sucesso que exija que um h2 siga um h1. O 1.3.1 Info and Relationships exige que a estrutura transmitida visualmente esteja disponível programaticamente — usar títulos de todo é a forma de o satisfazer. Saltar de h1 para h3 é desarrumado e piora a navegação com leitor de ecrã, mas não é o que o 1.3.1 diz. O axe-core classifica heading-order como boa prática, e há anos.

Idioma dos trechos. Esta estava errada duas vezes. O 3.1.2 é nível A, não AA — eu tinha o nível errado. E a verificação intitulava-se «Trechos em língua estrangeira devem declarar o seu idioma», o que prometia algo que nenhuma verificação automática consegue fazer: saber que um trecho está noutra língua quando nada o assinala. O que o código fazia na realidade era validar os atributos lang já presentes. É uma verificação útil. Não é a verificação que o título anunciava.

Então quais são os números verdadeiros

25 verificações. Dezoito correspondem a um critério de sucesso das WCAG 2.2, distribuídas por catorze critérios distintos de nível A e AA: 1.1.1, 1.3.1, 1.3.5, 1.4.2, 1.4.3, 1.4.4, 2.4.1, 2.4.2, 2.4.4, 2.5.8, 3.1.1, 3.1.2, 3.3.2 e 4.1.2.

Sete são boas práticas. Merecem correção, não são violações de conformidade.

Antes da auditoria, a página do produto dizia «25 verificações automatizadas nos níveis A e AA das WCAG 2.2» e listava o 4.1.1 entre os critérios cobertos. Ambas as afirmações eram falsas, e a segunda era verificavelmente falsa por quem tivesse lido a Recomendação 2.2.

Porque isto não é preciosismo

Aqui está a parte que me fez deixar de tratar isto como um problema de rótulos.

O plugin tem um gerador para as informações de acessibilidade que o European Accessibility Act exige. Preenche a secção de «barreiras conhecidas» a partir da análise mais recente e — este era o argumento de venda — associa a cada barreira o seu critério de sucesso WCAG.

Ou seja, oito regras que citavam critérios errados, obsoletos ou sem relação estavam a escrever esses números dentro de um documento que o dono do site publica como declaração legal sobre o seu próprio serviço.

Uma declaração de conformidade não é um relatório. Um relatório que exagera estraga-lhe a tarde. Uma declaração publicada que cita um critério inexistente, num documento que é legalmente obrigado a manter, é outra categoria de erro — e das que o seu cliente descobre, não você.

É este o argumento a favor da distinção, e é o único que importa. Uma ferramenta que apresenta cada achado como violação das WCAG infla dois números: o seu — 25 verificações WCAG lê-se melhor do que 18 — e o seu. E o seu número inflado é o que acaba em público.

O que mudei

Cada regra declara agora o que é:

{
    id: 'heading_order',
    wcag: '',
    level: '',
    standard: 'best-practice',
    ...
}

O relatório imprime o critério onde existe, e Boa prática onde não existe, em vez de um WCAG () vazio.

O gerador exige agora duas condições independentes antes de escrever um critério dentro de um documento legal: a regra tem de estar marcada como mapeada nas WCAG, e o seu valor tem de corresponder a ^\d+\.\d+\.\d+$. Qualquer uma das duas sozinha teria bastado para impedir o que aconteceu. Eu queria aquela que sobrevive a alguém editar a outra.

E os textos comerciais dizem agora 18 e 7, no readme, na documentação e na ficha do marketplace. Foi o commit menos agradável da semana e aquele que repetiria.

Se constrói ou compra uma destas ferramentas

Três perguntas que vale a pena fazer, e nenhuma exige que confie em mim.

Ainda reporta o 4.1.1? Trinta segundos para verificar, e diz-lhe quando o conjunto de regras foi lido contra a norma em vez de copiado de outra ferramenta.

Distingue critérios de sucesso de boas práticas? Se cada achado traz um número de critério, pelo menos alguns desses números são decoração. A implementação de referência sobre a qual este setor funciona marca cerca de um quarto das suas regras como boa prática. Uma ferramenta que não tem nenhuma não é mais rigorosa: é menos cuidadosa.

Para onde vai o critério depois do relatório? Se alimenta uma declaração, um selo, um PDF ou qualquer coisa que um cliente publique, a exatidão deixa de ser uma questão de qualidade interna.

A parte que não mudou

Os testes automatizados encontram cerca de um terço das barreiras reais de acessibilidade. Corrigir os rótulos não mexe nesse número. Um relatório limpo é um bom sinal, não uma declaração de conformidade, e os testes com teclado e leitor de ecrã feitos por uma pessoa continuam a ser a única forma de saber.

O que a auditoria mudou é mais estreito e, creio, valeu a semana: quando a minha ferramenta agora diz WCAG, é a sério.