Ficha 02 · ARIA, formulários, motion, auditoria
- ARIA básico
- Formulários acessíveis
- Motion
- Auditar
Parte I · ARIA
Exercício 1 · Regras de ouro (10 pts)
Indica 2 regras importantes ao usar ARIA.
- No ARIA é melhor que mau ARIA — usar o elemento HTML certo (
<button>,<nav>, etc.) é sempre melhor do que recriar comrole. - ARIA não muda comportamento, só anuncia —
role="button"num<div>não faz com que responda aEnter; tens de implementar à mão.
Bónus: 3) Não inventar atributos; usar só os do spec ARIA. 4) Testar sempre com leitor de ecrã real, não só axe.
Exercício 2 · Botão hamburger (15 pts)
Escreve o HTML de um botão hamburger que abre/fecha um menu, com ARIA correto.
<button
type="button"
aria-label="Abrir menu"
aria-expanded="false"
aria-controls="menu-principal"
class="hamburger"
>
<svg aria-hidden="true" viewBox="0 0 24 24" width="24" height="24">
<path d="M3 6h18M3 12h18M3 18h18" stroke="currentColor" stroke-width="2"/>
</svg>
</button>
<nav id="menu-principal" hidden>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/sobre">Sobre</a></li>
</ul>
</nav>
JS alterna aria-expanded (true/false) e o atributo hidden no <nav>. aria-label muda para "Fechar menu" quando aberto (opcional). <svg> decorativo → aria-hidden.
Exercício 3 · Toast vivo (10 pts)
Tens este toast que aparece após o utilizador guardar:
<div class="toast">Encomenda guardada.</div>
Que atributo ARIA falta para que um leitor de ecrã o anuncie automaticamente? E qual seria a diferença entre polite e assertive?
Falta aria-live (ou role="status" / role="alert"):
<div class="toast" role="status" aria-live="polite">
Encomenda guardada.
</div>
polite— anuncia quando o leitor estiver disponível (não interrompe). Para confirmações.assertive(ourole="alert") — interrompe imediatamente o leitor. Para erros críticos ou problemas de segurança. Usar com parcimónia (irritante se demais).
Parte II · Formulários
Exercício 4 · Refazer formulário (20 pts)
Este formulário tem 6 problemas de acessibilidade. Identifica-os e reescreve-o corretamente.
<form>
<div>Email</div>
<input type="text" placeholder="O teu email">
<div>Password</div>
<input type="text">
<div onclick="enviar()">Entrar</div>
</form>
Problemas:
1. Sem <label> — <div> não está associado ao input.
2. type="text" no email — devia ser type="email".
3. placeholder como label — desaparece ao escrever.
4. type="text" na password — devia ser type="password" (esconde caracteres).
5. Sem autocomplete — não ajuda gestores de password.
6. <div onclick> como submit — não focável, não submete por Enter, leitor não anuncia como botão.
Versão correta:
<form>
<label for="email">Email</label>
<input id="email" type="email" name="email" autocomplete="email" required>
<label for="pw">Password</label>
<input id="pw" type="password" name="password" autocomplete="current-password" required>
<button type="submit">Entrar</button>
</form>
Exercício 5 · Erro descritivo (10 pts)
O input do email falha a validação. Que mensagem mostrar (e como), em vez de só "Erro"?
<label for="email">Email</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-erro"
>
<p id="email-erro" role="alert" class="erro">
Email inválido — falta '@' antes do domínio (ex.: nome@dominio.com).
</p>
Características:
- Específica ("falta '@'", não "erro").
- Construtiva (dá exemplo).
- Inline (junto ao campo, não no topo).
- Anunciada via role="alert" e ligada ao input via aria-describedby.
Parte III · Motion
Exercício 6 · Reduced motion CSS (10 pts)
Escreve o CSS que desativa/encurta todas as animações e transições quando o utilizador pediu menos movimento.
@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;
}
}
(Versão "sledgehammer" segura. Idealmente desenhas variantes específicas — ex.: substituir um slide horizontal por um fade curto.)
Exercício 7 · Onde está o perigo (10 pts)
Indica 2 padrões de animação que podem ser problemáticos e porquê.
- Flashes > 3 por segundo numa área grande do ecrã — risco de convulsões em pessoas com epilepsia fotosensível (WCAG 2.3.1).
- Movimentos grandes (parallax pesado, slide-in de blocos grandes, zoom forte) — causam náusea, enxaqueca ou tonturas em pessoas com sensibilidade vestibular.
Bónus: 3) Autoplay com loop longo distrai pessoas com TDAH ou impede leitura. 4) Animações longas obrigatórias tornam o produto lento e irritante.
Parte IV · Auditar
Exercício 8 · Plano de teste (15 pts)
Acabaste de implementar uma página de checkout. Descreve 5 testes manuais que farias antes de considerar acessível (não basta correr o Lighthouse).
- Só teclado —
Tabpor todo o checkout; consegues preencher campos, mudar quantidade, escolher método de pagamento e finalizar? Foco visível em cada passo? - Leitor de ecrã (VoiceOver/NVDA) — começa do topo; cada campo é anunciado com label correto? Erros são lidos? Confirmação no final é anunciada?
- Zoom 200% — algum campo fica cortado? Botão "Pagar" desaparece? Scroll horizontal?
- Simulador de daltonismo (DevTools) — algum erro/badge depende só de cor (verde "OK" / vermelho "falta")?
- Mobile com TalkBack/VoiceOver — alvos são suficientes? Gestos funcionam?
Bónus: 6) Testar sem JavaScript se possível (graceful degradation). 7) Testar modo dark/light ambos com contraste.
Parte V · Cenário
Exercício 9 · Briefing (10 pts)
Um cliente pede um site institucional para o município. Que 3 requisitos legais e técnicos de acessibilidade colocarias logo no briefing?
- WCAG 2.1 nível AA como base obrigatória (cumprimento legal da Directiva UE 2016/2102; site público).
- Declaração de acessibilidade publicada e mantida (obrigatória para setor público) + mecanismo de feedback acessível (ex.: email + formulário acessível).
- Auditoria por terceiros antes do lançamento + plano de monitorização contínua (Pa11y CI, revisão trimestral, testes com utilizadores reais).
Bónus: 4) PDFs taggados ou substituídos por HTML. 5) LGP nos vídeos institucionais principais.