Curso de Acessibilidade para cegos
Leitores de tela, semântica, ARIA e teste — o protocolo completo para quem não enxerga.
A tese deste curso: acessibilidade não é "opcional" nem "extra". É uma regra permanente do estúdio (CLAUDE.md) e um direito. Um cego navega com leitor de tela + teclado — e o seu código precisa "falar" com ele: semântica correta, nomes acessíveis, foco visível e anúncios de mudança.
Curso interativo: há um simulador de leitor de tela, demos de foco e de aria-live, e um checklist final de auditoria (progresso salvo no navegador). Base: WCAG 2.2 AA + WAI-ARIA 1.3 (estado ago/2026).
Por que acessibilidade
~15% da população mundial vive com alguma deficiência; ~12 milhões de americanos com baixa visão dependem de leitor de tela. Acessibilidade é mercado, lei e ética.
Os números
- 71% dos usuários com deficiência abandonam um site inacessível (Click-Away Pound).
- ~15% de aumento médio de conversão após melhorias de acessibilidade (W3C).
- EUA: 4.605 ações judiciais de ADA relacionadas a acessibilidade em 2024; alta de 300% entre 2018 e 2024.
- Brasil: Lei Brasileira de Inclusão (13.146/2015) exige acessibilidade digital; e-MAG (governo federal) padroniza. Europa: European Accessibility Act em vigor.
Por que (também) é bom negócio
Site acessível é mais rápido, melhor rankeado (SEO — alt text, semântica h1-h6, HTML limpo) e mais fácil de usar por todos (quem navega no escuro, sem mouse, em telas pequenas, com leitura difícil). Acessibilidade é sinônimo de qualidade.
Os 4 princípios (POUR)
| Princípio | Significado | Exemplo |
|---|---|---|
| Perceptível | Informação apresentada de um jeito que o usuário percebe | alt em imagem, transcrição em vídeo |
| Operável | Interface usável (teclado, sem armadilha de foco) | Tudo funciona com Tab/Enter |
| Compreensível | Texto claro, previsível | lang correto, erros anunciados |
| Robusto | Funciona com tecnologias assistivas atuais e futuras | HTML semântico, ARIA correto |
Exercícios M1
- Ex.1.1 Em 3 linhas, por que acessibilidade é decisão de produto e não "polimento"?
- Ex.1.2 Nomeie um requisito legal brasileiro e um europeu.
- Ex.1.3 Liste 2 exemplos de cada princípio POUR.
Como um cego navega
O usuário cego não vê a tela: ouve tudo. O leitor de tela lê a árvore de acessibilidade do navegador — construída a partir do HTML/ARIA — e o usuário navega só com teclado, pulando por regiões, títulos, links e controles.
Os leitores de tela
| Leitor | Plataforma | Curiosidade |
|---|---|---|
| NVDA | Windows | Gratuito e o mais usado; melhor com Firefox |
| JAWS | Windows | Comercial, popular em empresas/governo |
| VoiceOver | macOS/iOS | Embutido no Apple |
| TalkBack | Android | Embutido; gestos de toque |
Como navega (na prática)
- Teclado: Tab/Shift+Tab entre controles; setas linha a linha; Enter ativa.
- Atalhos de estrutura: NVDA+F7 lista títulos/links/landmarks; Insert+F6 lista títulos (JAWS); "roda" (rotor) no VoiceOver pula por títulos, links, landmarks.
- Pular direto: o usuário salta para
main, lista os títulos e escolhe o que quer ouvir. Por isso semântica correta é tudo.
Simulador de leitor de tela (demo)
Exercícios M2
- Ex.2.1 Liste os 4 leitores de tela e suas plataformas.
- Ex.2.2 Por que títulos e landmarks importam tanto para um usuário de leitor?
- Ex.2.3 Teste o simulador e escreva 1 parágrafo sobre o que mudou de um modo para o outro.
Semântica e landmarks
A regra de ouro da acessibilidade: use o elemento nativo certo antes de qualquer ARIA. O HTML semântico já "fala" com o leitor de tela de graça.
O que o leitor espera
<html lang="pt-BR"> <!-- idioma para a pronúncia certa -->
<header> ... </header> <!-- banner -->
<nav aria-label="Principal"> ... </nav> <!-- navegação -->
<main> <h1>Título único</h1> ... </main> <!-- conteúdo -->
<footer> ... </footer> <!-- contentinfo -->
lang: sem ele, o leitor pronuncia em inglês ("João" vira "Ji-ou").- Landmarks:
header/nav/main/aside/footercriam as "regiões" que o usuário pula entre si. - Títulos
h1→h6em hierarquia lógica (um únicoh1por página). - Botões de verdade (
<button>), links, listas (ul/ol) — nuncadivclicável comonclick.
Primeira regra do ARIA
"Não use ARIA se o elemento nativo resolver." ARIA pode quebrar o que funcionava se usado errado (ex.: aria-hidden="true" num container com conteúdo importante esconde tudo do leitor). A ordem: HTML semântico → ARIA mínima → nada.
Contraste de exemplo: botão
// ❌ div clicável — o leitor não sabe que é botão, nem foca
<div onclick="salvar()">Salvar</div>
// ✅ botão nativo — foca, ativa com Enter/Espaço, anuncia "Salvar, botão"
<button type="button" onclick="salvar()">Salvar</button>
Exercícios M3
- Ex.3.1 Converta 3 elementos incorretos do seu projeto para HTML semântico (ex.:
divclicável →button). - Ex.3.2 Sua página tem um único
h1e hierarquia de títulos sem pulos? Verifique. - Ex.3.3 Cite 1 caso onde ARIA seria realmente necessária (e 1 onde não seria).
Nomes acessíveis
Todo elemento interativo precisa de um nome acessível — o texto que o leitor anuncia. Sem nome, um botão vira "botão" (e nada mais).
Como dar nome
| Elemento | Como nomear | Prioridade |
|---|---|---|
| Input/select | <label for> | 1º — placeholder NÃO é rótulo |
| Botão/link | Texto visível dentro | 1º — "Label in Name" (WCAG 2.5.3) |
| Ícone/svg | aria-label + role="img" (ou aria-hidden se decorativo) | 2º — quando não há texto visível |
| Imagem | alt | alt="" se decorativa |
Erros comuns (e o certo)
// ❌ placeholder como rótulo (some quando preenche; usuário perde o nome)
<input type="text" placeholder="Seu e-mail">
// ✅ label de verdade, visível e associada
<label for="email">Seu e-mail</label>
<input type="email" id="email">
// ❌ aria-label vazio — apaga o nome
<button aria-label=""><svg></svg></button>
// ✅
<button aria-label="Fechar"><svg></svg></button>
WCAG 2.5.3 "Label in Name": o nome acessível deve conter o texto visível. Nada de aria-label="Enviar formulário de contato" num botão que mostra "Enviar" — o usuário de voz (comando por fala) procura pelo que vê na tela.
Exercícios M4
- Ex.4.1 Liste 3 formulários/controles do seu projeto sem label e corrija.
- Ex.4.2 Encontre um ícone-só e dê
aria-labeldescritivo (ouaria-hiddense decorativo). - Ex.4.3 Verifique "Label in Name": o nome acessível contém o texto visível?
Teclado e foco
Um usuário cego não usa mouse. Tudo precisa ser operável por teclado, com foco visível e numa ordem lógica.
Os 4 requisitos de teclado
- Tudo operável: Tab/Shift+Tab entre controles; Enter/Espaço ativa; setas para opções.
- Foco visível:
:focus-visible { outline: 2px solid #00d4ff }— nuncaoutline: nonesem substituto. - Sem armadilha de foco: em modais/accordions, o foco não pode "ficar preso"; Escape fecha e devolve o foco.
- Skip link: link "Pular para o conteúdo" no início — o usuário não precisa Tab por 40 links de menu.
<a href="#conteudo" class="skip">Pular para o conteúdo</a>
...
<main id="conteudo"> ... </main>
/* CSS: só aparece quando recebe foco */
.skip{position:absolute;left:-9999px}
.skip:focus{left:0}
Controles customizados
Se você criar um accordion/tab/select customizado: role correto, aria-expanded, navegação por setas, tabindex gerenciado, e Enter/Espaço acionando. Prefira o elemento nativo quando existir.
Demo: ordem de foco
Ordem natural = ordem do DOM. Não use tabindex positivo (reordena de forma imprevisível); use a ordem do documento.
Exercícios M5
- Ex.5.1 Navegue sua página só com Tab e anote onde o foco some ou fica preso.
- Ex.5.2 Adicione um skip link se não existir.
- Ex.5.3 Verifique se todo controle customizado responde a Enter/Espaço e setas.
Conteúdo dinâmico (aria-live)
Se a página muda sem navegação (toast, contador, erro de formulário), o leitor de tela precisa ser avisado. É o papel das live regions.
aria-live na prática
// Área que "escuta" mudanças e anuncia quando atualiza
<div role="status" aria-live="polite">Item adicionado ao carrinho</div>
// Erro crítico — anuncia imediatamente (interrompe)
<div role="alert">E-mail inválido</div>
// O usuário não perde o lugar: polite espera a frase atual terminar.
| Atributo | Quando | Exemplo |
|---|---|---|
aria-live="polite" / role="status" | Mudança útil mas não urgente | contagem de resultados, confirmação de ação |
aria-live="assertive" / role="alert" | Urgente, interrompe | erro de formulário, perda de conexão |
aria-atomic="true" | Anunciar a região inteira, não só o trecho mudado | contador que muda só o número |
Regra prática: atualize a área com o texto inteiro (não concatenar no JS repetidamente) e não use polite para cada micro-mudança — enche o usuário de anúncios (barulho).
Demo: live region
Exercícios M6
- Ex.6.1 Encontre 2 mudanças dinâmicas no seu projeto sem aria-live e adicione.
- Ex.6.2 Erro de formulário: ele está em
role="alert"? - Ex.6.3 Teste a demo e anote o que o leitor anunciaria.
Gráficos, imagens e cor
Imagem e gráfico precisam de equivalente textual; e nenhuma informação pode depender só de cor.
Imagens
| Caso | alt |
|---|---|
| Imagem informativa | alt="Gráfico de vendas: alta de 12% em agosto" — descreve a informação, não a estética |
| Decorativa | alt="" (vazio) — o leitor a ignora |
| Botão-imagem | alt = ação ("Fechar") |
| Gráfico SVG (como os dos nossos cursos) | role="img" + aria-label explicando o que mostra, ou um resumo em texto ao lado para dados densos |
Gráficos de dados: o essencial
- Sempre dê o resumo executivo em texto ("a receita subiu 12% no trimestre") — ninguém lê eixo.
- Para dados densos, ofereça a tabela de dados (a mesma informação em texto tabular).
- SVG interativo:
role="img"+aria-labelno container, e os elementos internosaria-hidden(senão o leitor lê cada retângulo).
Cor e contraste
- Contraste ≥ 4,5:1 para texto normal (WCAG AA); 3:1 para texto grande e UI.
- Nunca só cor: estado de erro = cor + ícone + texto ("Erro: e-mail inválido"), não só vermelho.
- Valide com simuladores de daltonismo (e não confie em si: ~8% dos homens têm daltonismo).
Regra de ouro para alt: "se a imagem fosse removida, o texto faria falta?" — se não, alt="". Descreva a informação, não a aparência ("foto de um homem sorrindo de terno" raramente é útil).
Exercícios M7
- Ex.7.1 Audite as imagens do seu site: todas têm alt correto (ou alt="")?
- Ex.7.2 Pegue um gráfico seu e escreva o resumo em texto que um leitor deve ouvir.
- Ex.7.3 Os estados de erro do seu app dependem só de cor?
Testes e ferramentas
Automação pega só 30–50% dos problemas. O resto é manual: teclado + leitor de tela + bom senso.
Automatizado (rápido, não suficiente)
| Ferramenta | O que faz |
|---|---|
| axe DevTools | Extensão; varre WCAG; acha ARIA errado, label ausente, contraste |
| Lighthouse | Chrome DevTools → categorias; nota 0–100 de a11y |
| WAVE | Extensão; marca visualmente os erros na página |
| pa11y / jest-axe | Linha de comando / CI — falha o build com violações |
# Exemplo: rodar axe-core no CI (jest-axe)
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
it('modal sem violações', async () => {
const { container } = render(<Modal />);
expect(await axe(container)).toHaveNoViolations();
});
Manual (o que automação não vê)
- Só teclado: completar o fluxo inteiro (menu, formulário, modal) sem mouse.
- NVDA + Firefox (Windows) e VoiceOver + Safari (Mac): navegar por títulos/links/landmarks e ouvir os anúncios.
- Atalhos úteis: NVDA+F7 (lista de elementos), Insert+F6 (títulos, JAWS), rotor do VoiceOver (Ctrl+Option+U).
- Zoom 200% e sem CSS (a ordem lógica continua correta?).
Checklist final de auditoria (WCAG 2.2 AA essencial)
Exercícios M8
- Ex.8.1 Rode o Lighthouse (categoria Accessibility) nos seus cursos/sites e anote o score.
- Ex.8.2 Faça um fluxo completo só com teclado e anote os problemas.
- Ex.8.3 Ouça o seu site com o NVDA (ou VoiceOver) e descreva 1 melhoria de anúncio.
Fontes e links
- WCAG 2.2 (W3C): w3.org/TR/WCAG22 · visão geral: W3C WAI
- WAI-ARIA 1.3: w3.org/TR/wai-aria-1.3 · ARIA Authoring Practices Guide: WAI/ARIA/apg
- MDN — Acessibilidade: MDN ARIA · Accessibility
- Screen Reader Testing Best Practices: skynettechnologies.com
- ARIA Labels — guia completo: allaccessible.org
- Ferramentas: axe DevTools · NVDA (gratuito) · WAVE
- Brasil: e-MAG / gov.br acessibilidade · Lei Brasileira de Inclusão (13.146/2015)
⚠️ WCAG/ARIA evoluem — este curso reflete WCAG 2.2 + ARIA 1.3 (ago/2026); a WCAG 3.0 está em elaboração.