🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

Guia de acessibilidade da Web 2026: WCAG 2.2, ARIA e testes

⏱️6 min read  ·  1,183 words

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.

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.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা