A acessibilidade na Web (a11y) garante que sites e aplicativos funcionem para todos — incluindo pessoas com deficiências visuais, motoras, auditivas e cognitivas. Em 2026, as WCAG 2.2 são o padrão global, e os processos judiciais de acessibilidade tornaram tudo um requisito legal para a maioria das empresas. Este guia cobre o essencial que todo desenvolvedor deve saber.
📋 Table of Contents
Por que a acessibilidade é importante
- 1 bilhão de pessoasem todo o mundo têm uma deficiência
- Requisito legalnos EUA (ADA), UE (EAA) e na maioria dos países
- Benefício de SEO– o código amigável para leitores de tela também é amigável para mecanismos de pesquisa
- Melhor UX para todos– as legendas ajudam em ambientes barulhentos, a navegação pelo teclado ajuda usuários avançados
WCAG 2.2 — Os Quatro Princípios (POUR)
- Perceptível— os usuários podem ver/ouvir conteúdo (texto alternativo, legendas)
- Operável— os usuários podem navegar (teclado, sem conteúdo indutor de convulsões)
- Compreensível— o conteúdo é claro (texto legível, mensagens de erro)
- Robusto— trabalha com tecnologias assistivas
Técnicas Essenciais
1. HTML semântico
<!-- BAD: div soup -->
<div class="header">
<div class="nav">
<div onclick="go('/')">Home</div>
</div>
</div>
<!-- GOOD: semantic HTML -->
<header>
<nav aria-label="Main navigation">
<a href="/">Home</a>
</nav>
</header>
<!-- Use semantic elements for meaning -->
<main> <!-- primary content -->
<article> <!-- self-contained content -->
<section> <!-- thematic grouping -->
<aside> <!-- tangentially related -->
<figure> <!-- image with caption -->
<figcaption> <!-- caption for figure -->
<button> <!-- interactive element (not div!) -->
2. Imagens e texto alternativo
<!-- Informative image: describe what image conveys -->
<img src="chart.png" alt="Bar chart showing 40% increase in revenue Q1 2026" />
<!-- Decorative image: empty alt (screen readers skip) -->
<img src="divider.svg" alt="" role="presentation" />
<!-- Complex image: describe in text or use longdesc -->
<figure>
<img src="complex-graph.png" alt="Architecture diagram described below" />
<figcaption>
System architecture with three tiers: frontend (React),
API (FastAPI), and database (PostgreSQL).
</figcaption>
</figure>
<!-- Icon with text: hide icon from AT -->
<button>
<svg aria-hidden="true" focusable="false">...</svg>
Download PDF
</button>
<!-- Icon only: add visually hidden label -->
<button aria-label="Close dialog">
<svg aria-hidden="true">...</svg>
</button>
3. Navegação pelo teclado
<!-- ALL interactive elements must be keyboard accessible -->
<!-- Use button for actions, a for navigation -->
<button onclick="openModal()">Open</button> <!-- enter/space activates -->
<a href="/about">About</a> <!-- enter activates -->
<!-- Custom interactive element: add tabindex + keyboard handler -->
<div
role="button"
tabindex="0"
onclick="handleClick()"
onkeydown="if(event.key==='Enter'||event.key===' ')handleClick()"
>
Custom Button
</div>
<!-- Skip link: helps keyboard users jump to main content -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<header>...</header>
<main id="main-content">...</main>
<!-- Never remove focus outline without replacement -->
/* BAD */
:focus { outline: none; }
/* GOOD */
:focus-visible {
outline: 3px solid #0066CC;
outline-offset: 2px;
}
4. ARIA (aplicativos ricos e acessíveis para Internet)
<!-- Use ARIA only when HTML semantics aren't enough -->
<!-- aria-label: provides accessible name -->
<button aria-label="Close dialog">✕</button>
<!-- aria-labelledby: references visible text -->
<h2 id="dialog-title">Confirm Delete</h2>
<div role="dialog" aria-labelledby="dialog-title">...</div>
<!-- aria-describedby: provides description -->
<input
id="email"
type="email"
aria-describedby="email-hint"
/>
<p id="email-hint">We'll never share your email.</p>
<!-- aria-live: announce dynamic content changes -->
<div aria-live="polite" aria-atomic="true">
<!-- Screen reader announces when content changes -->
Form submitted successfully!
</div>
<!-- aria-expanded: collapsible elements -->
<button aria-expanded="false" aria-controls="menu">Menu</button>
<ul id="menu" hidden>...</ul>
<!-- aria-invalid: form validation -->
<input aria-invalid="true" aria-describedby="email-error" />
<p id="email-error" role="alert">Invalid email format</p>
5. Cor e contraste
/* WCAG AA: 4.5:1 for normal text, 3:1 for large text */
/* WCAG AAA: 7:1 for normal text */
/* Check contrast: use WebAIM Contrast Checker */
/* Good contrast */
color: #1a1a1a; /* very dark gray on white: 18.1:1 */
background: #0066CC;
color: white; /* white on blue: 5.4:1 — AA pass */
/* Bad contrast (avoid) */
color: #aaa; /* light gray on white: 2.3:1 — FAIL */
/* Never rely on color alone to convey information */
/* Bad: red text = error, green = success */
/* Good: add icon + text label + color */
.error::before { content: "⚠ Error: "; }
/* Focus indicators must meet contrast requirements too */
:focus-visible {
outline: 3px solid #0066CC; /* sufficient contrast */
}
Testando acessibilidade
# Automated testing (catches ~30-40% of issues)
npm install --save-dev axe-core @axe-core/playwright
# Run axe in Playwright
import { checkA11y } from 'axe-playwright';
await checkA11y(page, null, { runOnly: ['wcag2a', 'wcag2aa'] });
# Browser extensions
# - axe DevTools (Chrome/Firefox) — most comprehensive
# - Lighthouse (Chrome DevTools) → Accessibility score
# - WAVE (WebAIM) — visual overlay
# Manual testing checklist:
# ☐ Navigate entire page with Tab key only
# ☐ Test with screen reader (NVDA/JAWS Windows, VoiceOver Mac/iOS)
# ☐ Zoom to 200% — does nothing overlap?
# ☐ Turn off CSS — is content readable in order?
# ☐ Check color contrast with DevTools
Acessibilidade de reação
// React-specific a11y patterns
// 1. Form labeling
function EmailInput() {
return (
<div>
<label htmlFor="email">Email address</label>
<input id="email" type="email" autoComplete="email" />
</div>
);
}
// 2. Focus management in modals
function Dialog({ isOpen, onClose }: Props) {
const dialogRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (isOpen) dialogRef.current?.focus(); // trap focus
}, [isOpen]);
return isOpen ? (
<div
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
tabIndex={-1}
ref={dialogRef}
>
<h2 id="dialog-title">Confirm Action</h2>
<button onClick={onClose}>Cancel</button>
</div>
) : null;
}
// 3. Live region for dynamic content
function StatusMessage({ message }: { message: string }) {
return (
<div aria-live="polite" aria-atomic="true">
{message}
</div>
);
}
A acessibilidade da Web em 2026 é um requisito legal e uma vantagem comercial. Comece com HTML semântico (80% de a11y vem do HTML correto), garanta a navegabilidade do teclado, adicione texto alternativo a todas as imagens e mantenha o contraste das cores. Use ax DevTools para verificações automatizadas e teste com VoiceOver/NVDA para validação no mundo real.
🔗 Share this article
✍️ Leave a Comment