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.
| Regra | Declarava | Na realidade |
|---|---|---|
| Id duplicados | 4.1.1 | Removido das WCAG 2.2 |
Um único landmark main |
1.3.6 AAA | 1.3.6 é Identify Purpose, um critério sem relação |
| Idioma dos trechos | 3.1.2 AA | 3.1.2 é nível A — e a verificação não fazia o que o título prometia |
| Texto de link vago | 2.4.4 | O 2.4.4 é satisfeito pelo contexto |
| Níveis de título saltados | 1.3.1 | As WCAG não exigem níveis sequenciais |
h1 em falta |
1.3.1 | Boa prática |
| Título vazio | 1.3.1 | Boa prática |
tabindex positivo |
2.4.3 | Boa 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.