Um guia para desenvolvedores sobre rótulos ARIA que realmente ajudam
Rótulos ARIA não são uma camada mágica de acessibilidade. Bem usados, tornam os controles compreensíveis. Usados de forma casual, escondem texto útil e criam interfaces confusas.
Tabela de conteúdos
- Rótulos ARIA servem para nomes, não para desculpas
- O nome acessível, em inglês simples
- Primeira regra: prefira HTML nativo e rótulos visíveis
- Quando `aria-label` é a ferramenta certa
- Quando `aria-label` é a ferramenta errada
- Use `aria-labelledby` quando já houver texto visível
- Use `aria-describedby` para texto de ajuda, não para o nome
- Controles repetidos precisam de nomes únicos
- Não rotule tudo
- Verifique o nome calculado, não apenas o código
- Uma checklist prática de revisão
- A disciplina silenciosa de um bom ARIA
Rótulos ARIA servem para nomes, não para desculpas
ARIA é útil, mas muitas vezes é usado como remendo para HTML pouco claro. É aí que as equipes se complicam.
O exemplo mais comum é aria-label. Parece inofensivo: adicionar uma string, satisfazer um linter e seguir em frente. Mas um nome acessível não é decoração. É o nome que muitas tecnologias assistivas expõem aos usuários quando eles navegam por botões, links, campos de formulário, títulos, landmarks e controles.
Se esse nome for vago, duplicado, desatualizado ou diferente do rótulo visível, a interface fica mais difícil de usar. Às vezes, pior: aria-label pode sobrescrever um texto melhor que já estava presente no DOM.
O objetivo não é adicionar mais ARIA. O objetivo é tornar claros o nome, a função, o estado e a finalidade de cada elemento da interface.
O nome acessível, em inglês simples
A maioria dos elementos interativos tem um nome acessível. Leitores de tela usam esse nome para anunciar o que o elemento é.
Por exemplo:
<button>Save changes</button>
Um leitor de tela pode anunciar algo como: “Save changes, button.” A função vem do elemento button nativo. O nome vem do texto dentro dele.
Esse é o caso ideal: o texto visível e o nome acessível correspondem.
Atributos de rotulagem ARIA se tornam úteis quando a interface visível não fornece um nome completo, ou quando o nome precisa vir de outro elemento. Os principais atributos são:
aria-label: fornece uma string diretamente no elemento.aria-labelledby: aponta para um ou mais elementos cujo texto se torna o nome.aria-describedby: aponta para um texto de descrição complementar, não para o nome principal.
Esses três são relacionados, mas não intercambiáveis.
Primeira regra: prefira HTML nativo e rótulos visíveis
Se você puder colocar texto visível no controle, faça isso primeiro.
Isto é melhor:
<button>Delete invoice</button>
Do que isto:
<button aria-label="Delete invoice">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
O segundo padrão é válido para um botão somente com ícone. Mas, se o design puder tolerar texto visível, esse texto ajuda todo mundo: usuários de leitores de tela, usuários de reconhecimento de fala, pessoas sob carga cognitiva, pessoas fazendo uma varredura rápida e pessoas usando ferramentas de tradução.
Este é um tema recorrente no trabalho de acessibilidade. HTML nativo e affordances visíveis resolvem mais problemas do que metadados ocultos. O mesmo princípio se aplica à semântica de botões de forma mais ampla; se sua equipe está auditando controles de UI, nossa checklist para botões web acessíveis é um bom complemento para este guia.
Quando aria-label é a ferramenta certa
Use aria-label quando um elemento precisa de um nome acessível e não há texto visível adequado para referenciar.
O caso clássico é um botão somente com ícone:
<button aria-label="Search">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<!-- icon -->
</svg>
</button>
Isso é razoável. O ícone visível sugere busca, mas o caminho SVG em si não fornece um nome confiável. O aria-label fornece um.
Outros bons casos incluem:
- Um botão de fechar representado apenas por um “X”.
- Um landmark de navegação que precisa de um nome mais específico, como
aria-label="Product". - Um controle repetido em que o contexto visível não faz parte do texto do botão.
Por exemplo:
<nav aria-label="Primary">
...
</nav>
<nav aria-label="Footer">
...
</nav>
Ambos são landmarks de navegação, mas seus rótulos ajudam os usuários a distingui-los ao se moverem por landmarks.
Quando aria-label é a ferramenta errada
Não adicione aria-label só porque um teste diz que um elemento precisa de um rótulo. Corrija a marcação primeiro.
Ruim:
<div role="button" tabindex="0" aria-label="Submit">Submit</div>
Melhor:
<button>Submit</button>
O primeiro exemplo cria trabalho desnecessário. Agora você precisa recriar o comportamento de teclado, estados desabilitados, comportamento de formulário e expectativas que botões nativos já oferecem.
Também evite usar aria-label para renomear texto visível de uma forma que mude o significado.
<button aria-label="Delete invoice">Remove</button>
Isso parece pequeno, mas pode confundir usuários que dependem de entrada por fala. Se um botão visível diz “Remove”, mas seu nome acessível é “Delete invoice”, um usuário tentando dizer “click Remove” talvez não obtenha o resultado esperado. O requisito “label in name” da WCAG existe exatamente por esse motivo: o texto visível geralmente deve estar contido no nome acessível.
Uma versão melhor:
<button aria-label="Remove invoice">Remove</button>
Muitas vezes, melhor ainda:
<button>Remove invoice</button>
Use aria-labelledby quando já houver texto visível
Se o texto do rótulo já está na página, aria-labelledby geralmente é melhor do que aria-label.
Exemplo:
<h2 id="billing-title">Billing address</h2>
<section aria-labelledby="billing-title">
...
</section>
O nome acessível da seção agora vem do título visível. Você evita duplicar strings, o que reduz erros de tradução e rótulos desatualizados.
Isso é especialmente útil para grupos de formulário:
<fieldset aria-labelledby="shipping-speed-title">
<legend id="shipping-speed-title">Shipping speed</legend>
<label>
<input type="radio" name="shipping" value="standard">
Standard
</label>
<label>
<input type="radio" name="shipping" value="express">
Express
</label>
</fieldset>
Em muitos casos, o legend nativo é suficiente sem ARIA. O ponto é que rótulos visíveis devem liderar. ARIA deve conectar significado existente, não criar uma segunda versão privada dele.
Use aria-describedby para texto de ajuda, não para o nome
Uma descrição não é um rótulo.
Considere este campo:
<label for="password">Password</label>
<input id="password" type="password" aria-describedby="password-help">
<p id="password-help">Use at least 12 characters.</p>
O nome acessível é “Password.” A descrição é “Use at least 12 characters.” Um leitor de tela pode anunciar ambos, mas eles servem a propósitos diferentes.
Não faça isto:
<input type="password" aria-label="Use at least 12 characters">
Isso nomeia o campo pela instrução, não pelo conceito. Um usuário navegando por um formulário quer saber primeiro o que é o campo e depois quais restrições se aplicam.
Essa distinção também importa em estados de erro:
<label for="email">Email</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
>
<p id="email-error">Enter an email address in the format [email protected].</p>
O rótulo permanece estável. A mensagem de erro se torna contexto complementar.
Controles repetidos precisam de nomes únicos
Listas e cards são onde rótulos ARIA muitas vezes se tornam necessários.
Ruim:
<button>Delete</button>
<button>Delete</button>
<button>Delete</button>
Um usuário de leitor de tela navegando por botões pode ouvir “Delete, button” três vezes sem contexto.
Bom:
<button aria-label="Delete report: Q4 revenue">Delete</button>
<button aria-label="Delete report: Hiring plan">Delete</button>
<button aria-label="Delete report: Vendor list">Delete</button>
Este é um uso legítimo de aria-label: o texto visível permanece conciso, enquanto o nome acessível inclui o objeto.
Mas use esse padrão com cuidado. Se o nome do objeto estiver visível por perto, aria-labelledby pode ser mais fácil de manter:
<article>
<h3 id="report-q4">Q4 revenue</h3>
<button aria-labelledby="delete-q4 report-q4" id="delete-q4">Delete</button>
</article>
O nome acessível se torna “Delete Q4 revenue.” Isso evita duplicar o título do relatório em um atributo.
Não rotule tudo
Nem todo elemento precisa de um rótulo ARIA.
Texto estático geralmente não precisa. Ícones decorativos não precisam. Contêineres não precisam, a menos que tenham uma função significativa de landmark ou widget. Rotular em excesso pode deixar uma página barulhenta e mais difícil de navegar.
Para imagens, use o modelo específico de imagens: imagens significativas precisam de alt útil; imagens decorativas precisam de alt="" vazio. Não use rótulos ARIA como substituto para um bom texto de imagem. Se sua equipe está misturando esses conceitos, revisite texto alt pragmático para imagens e separe alternativas de imagem de nomes de controles.
Um erro comum é dar um aria-label a todo SVG. Se o SVG está dentro de um botão e o botão já tem um nome, o ícone geralmente deve ser ocultado das tecnologias assistivas:
<button aria-label="Open menu">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
Caso contrário, o usuário pode ouvir anúncios redundantes ou estranhos, dependendo da combinação de navegador e tecnologia assistiva.
Verifique o nome calculado, não apenas o código
Bugs de acessibilidade muitas vezes sobrevivem à revisão de código porque a marcação parece plausível.
Ferramentas modernas de desenvolvedor nos navegadores podem mostrar a árvore de acessibilidade calculada. No Chrome, Edge, Firefox e Safari, inspecione o elemento e procure informações de acessibilidade como função, nome e descrição. Você está verificando três coisas:
- A função é a que você espera?
- O nome acessível é claro e específico?
- A descrição ajuda sem substituir o nome?
Depois teste alguns fluxos com um leitor de tela real. Você não precisa se tornar especialista em tecnologia assistiva em tempo integral para perceber o básico. No macOS, o VoiceOver vem integrado. No Windows, o NVDA é amplamente usado e gratuito. Em dispositivos móveis, teste com VoiceOver no iOS e TalkBack no Android quando relevante.
Ferramentas automatizadas são úteis, mas não conseguem dizer de forma confiável se “Open”, “Read more” ou “Delete” têm contexto suficiente. Trate a automação como uma rede, não como um juiz. Isso é parecido com auditoria de performance: um relatório pode apontar áreas suspeitas, mas você ainda precisa interpretar o impacto. A mesma abordagem calma que recomendamos para ler um relatório do Lighthouse sem entrar em pânico se aplica aqui.
Uma checklist prática de revisão
Antes de publicar rótulos ARIA, pergunte:
- Isto poderia ser HTML nativo em vez disso?
- Há texto visível que deveria ser usado como rótulo?
- Se existe texto visível, o nome acessível o inclui?
- Controles repetidos são únicos quando navegados fora do contexto visual?
- O texto de ajuda está conectado com
aria-describedby, não forçado para dentro do rótulo? - Ícones decorativos estão ocultos das tecnologias assistivas?
- Alguém verificou o nome de acessibilidade calculado nas ferramentas de desenvolvedor do navegador?
- Pelo menos uma passagem com leitor de tela real foi feita no fluxo crítico?
Essa checklist captura a maioria dos problemas de rótulo antes que eles se tornem problemas para usuários.
A disciplina silenciosa de um bom ARIA
Um bom trabalho com ARIA raramente é dramático. É, em grande parte, contenção.
Use botões reais. Use rótulos reais. Mantenha nomes visíveis e acessíveis alinhados. Adicione aria-label apenas quando não houver uma fonte visível melhor. Use aria-labelledby quando a página já contém o texto certo. Use aria-describedby para instruções complementares e erros.
A plataforma web dá muito de graça aos desenvolvedores quando a usamos diretamente. ARIA existe para as lacunas. A habilidade está em saber quando há realmente uma lacuna.