Acessibilidade de Frontend
Aplica-se a componentes em <ui-packages-dir> e páginas em <web-dir>/src/. O
alvo é WCAG 2.1 Nível AA, e é um piso, não uma meta.
Resolvendo convenções do projeto
Valores entre colchetes angulares vêm do perfil de stack do projeto. Resolva-os nesta ordem:
- Leia
STACK-PROFILE.mdna raiz do repositório e use seus valores literalmente. - Se estiver ausente ou uma chave estiver faltando, infira do repositório —
css-strategyeui-frameworka partir das dependências da aplicação web. - Se ainda não resolvido, corresponda à convenção dominante já presente no repositório.
- Apenas quando o repositório estiver vazio, recorra ao padrão declarado desta skill — então escreva
os valores escolhidos em
STACK-PROFILE.md.
Nunca invente uma nova convenção quando o repositório já expressa uma.
Regras rígidas
1. HTML semântico primeiro
<button>para ações,<a>para navegação. Nunca um<div>com um manipulador de clique.- Níveis de cabeçalho descem sem pular.
<label>para cada campo de formulário, associado comhtmlFor.<fieldset>e<legend>para controles agrupados.- Marcos —
<nav>,<main>,<footer>,<aside>— em cada página.
2. ARIA apenas onde HTML não pode
A ordem de preferência é elemento semântico, depois atributo ARIA, depois comportamento
personalizado. Nunca use ARIA para substituir a semântica que um elemento já carrega — um
role="button" em um <div> reimplementa, mal, o que <button> fornece de graça.
Um ARIA incorreto é pior do que nenhum: um aria-label errado substitui silenciosamente o
nome acessível que um leitor de tela computaria corretamente.
3. Operação por teclado é obrigatória
- Tudo que é interativo é alcançável com Tab.
- Ordem de tabulação segue a ordem visual.
- Foco é sempre visível. Nunca remova um contorno sem substituí-lo.
Escapefecha diálogos e popovers;EntereSpaceativam controles; teclas de seta movem dentro de widgets compostos.- Widgets personalizados gerenciam o foco explicitamente.
4. Cor e contraste
- 4,5:1 para texto normal, 3:1 para texto grande (18px, ou 14px negrito) e para limites de IU significativos.
- Cor nunca carrega significado sozinha — combine-a com texto, um ícone ou um padrão.
- Ambos os temas são verificados, não apenas o padrão.
5. Imagens e mídia
- Toda imagem tem
alt. Descritivo para conteúdo,alt=""para decoração. - Nunca "imagem", "foto" ou o nome do arquivo.
- Imagens complexas recebem uma descrição longa através de
aria-describedbyou uma legenda. - Vídeo carrega legendas; áudio carrega uma transcrição.
6. Formulários
- Cada entrada rotulada.
- Erros vinculados com
aria-describedbye anunciados comrole="alert". - Campos inválidos marcados com
aria-invalid. - Campos obrigatórios marcados com o atributo
required— e se um asterisco for mostrado, seu significado é declarado em texto em algum lugar. - Em uma submissão falha, o foco move-se para o primeiro campo inválido.
7. Tamanho de alvo
WCAG 2.1 AA não tem tamanho mínimo de alvo (2.2 AA define 24×24 CSS px; o valor 44×44 é 2.1 AAA e a convenção HIG da plataforma). Trate 44×44 como o piso para ações primárias em superfícies de toque, e aplique-o da seguinte forma:
- Ações primárias e destrutivas, e qualquer coisa que um usuário alcança em um telefone: 44×44.
- Chrome denso de desktop — barras de ferramentas, ações de linhas de tabelas, controles de formulário compactos — pode ser menor, até 24×24, desde que os alvos não estejam adjacentes a outros alvos e um controle de tamanho completo equivalente exista em outro lugar.
- Espaçamento conta. Um controle de 32px com 6px de espaço livre de cada lado atende ao critério 2.2; um controle de 32px encostado no vizinho não.
Bibliotecas de componentes terceirizados geralmente vêm abaixo deste piso — uma altura de botão padrão
de 32 ou 36 CSS px é comum. Não edite manualmente o arquivo terceirizado para corrigi-lo, e
não trate a incompatibilidade como aceitável por padrão. Aumente o padrão em
<wrappers-pkg> para que cada consumidor herde o tamanho conforme, e mantenha os tamanhos
menores disponíveis como adesões explícitas para contextos densos. Dessa forma, a escolha acessível
é aquela que você obtém sem pensar nisso.
Registre qual resolução o projeto tomou em STACK-PROFILE.md. Uma isenção não declarada
é redescoberta como um bug a cada seis meses.
8. Movimento
- Respeite
prefers-reduced-motion. - Conteúdo de reprodução automática tem um controle de pausa.
- Nada pisca mais de três vezes por segundo.
9. Testar faz parte do trabalho
- Opere o recurso apenas com o teclado.
- Ouça-o com um leitor de tela — VoiceOver no macOS, NVDA no Windows.
- Execute uma varredura automatizada no conjunto de testes end-to-end.
Ferramentas automatizadas capturam aproximadamente um terço dos problemas reais. Elas são um piso, não uma aprovação.
Padrões
Implementações completas estão em
references/component-patterns.md. O que cada
padrão garante:
- Botão — um
<button>semântico cujo anel de foco aparece para usuários de teclado mas não para cliques de mouse (focus-visible), com transições seguras para movimento e uma propariaLabelpara uso apenas com ícone. - Campo de formulário — um campo rotulado cujo texto de erro é vinculado programaticamente
com
aria-describedby, anunciado comrole="alert", e sinalizado comaria-invalid; o asterisco de obrigatório éaria-hidden. - Diálogo — um
<dialog>nativo usandoshowModal()para captura de foco gratuita, tratamento deEscapee fundo inerte; o foco entra ao abrir e retorna ao gatilho ao fechar. - Listbox — um select personalizado com navegação de seta rotativa e fiação ARIA correta
(
aria-activedescendant,role="listbox"); construa-o apenas quando um<select>nativo não se encaixa. - Link de pular — permite que usuários de teclado pulem a navegação, visível apenas quando
focado; o alvo carrega
tabIndex={-1}para que o foco chegue lá.
Referência rápida WCAG
| Princípio | Requisito | Na prática |
|---|---|---|
| Perceptível | Conteúdo disponível para todos os sentidos | Texto alternativo, legendas, cor mais ícone |
| Operável | Tudo alcançável por teclado | Ordem de tabulação, Escape fecha, foco visível |
| Compreensível | Previsível, redigido claramente | Navegação consistente, linguagem simples |
| Robusto | Funciona com tecnologia assistiva | HTML válido, ARIA correto, elementos semânticos |
| Problema | Correção |
|---|---|
| Campo não rotulado | Adicione <label htmlFor> |
| Baixo contraste | Atenda a 4,5:1, ou 3:1 para texto grande |
| Sem caminho de teclado | Elementos interativos reais, foco gerenciado |
| Alt ausente | Descreva, ou alt="" se decorativo |
| Significado apenas por cor | Adicione texto ou um ícone |
| Botão apenas com ícone | Adicione aria-label |
| Conteúdo piscante | Mantenha abaixo de três flashes por segundo |
Preferências de movimento
Lide com movimento reduzido em CSS puro. Uma variante de classe utilitária como motion-safe:
só se aplica quando o movimento é permitido, então colocá-la dentro de uma consulta de movimento reduzido
produz uma regra que nunca pode corresponder.
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
Próximo de zero em vez de none mantém os eventos de final de transição disparando, para que componentes
que dependem deles não travem.
Para controle por componente, aplique a variante motion-safe: à própria utilidade de animação —
motion-safe:transition-colors, como no Botão acima.
Conteúdo visualmente oculto
A maioria dos frameworks de utilitários já fornece sr-only e not-sr-only. Use-os; não os
redefina. Se o seu não fornecer, a implementação de referência está em
references/component-patterns.md.
Checklist de teste
Teclado
- Todo elemento interativo alcançável por Tab
- Ordem de tabulação corresponde à ordem visual
- Foco sempre visível
- Escape fecha diálogos e popovers
- Teclas de seta funcionam em widgets compostos
- Foco retorna ao gatilho quando um diálogo fecha
Leitor de tela
- Todo conteúdo alcançável
- Propósitos de controle claros sem contexto circundante
- Rótulos anunciados com seus campos
- Erros anunciados através de
role="alert" - Marcos presentes
- Elementos decorativos ocultos com
aria-hidden
Cor
- 4,5:1 texto normal, 3:1 texto grande e limites de IU
- Nenhum significado apenas por cor
- Ambos os temas verificados
Movimento
- Movimento reduzido respeitado
- Nenhum piscar além de três por segundo
- Conteúdo de reprodução automática pausável
Automatizado
Varreduras executadas dentro do conjunto Playwright — veja frontend-testing. O trecho Axe-no-Playwright
está em
references/component-patterns.md.
Documentos de referência
| Aprofundamento | Referência |
|---|---|
| Implementações de componentes acessíveis: botão, campo de formulário, modal, listbox, link de pular | references/component-patterns.md |
Skills relacionadas
frontend-architecture— camadas de componentes e temasfrontend-testing— onde essas verificações são executadasfrontend-component-docs— documentando o contrato de acessibilidade de um componente