<p><strong>Meta Description:</strong> Aprenda testes de acessibilidade: WCAG 2.1, axe-core, Lighthouse, testes manuais e como garantir que seus apps são acessíveis.</p>

<hr>
<h2>Por Que Acessibilidade Importa?</h2>

<ul><li><strong>1.3 bilhões</strong> de pessoas com deficiência no mundo</li><ol><li><strong>Leis</strong> como ADA, LGPD, EU Accessibility Act</li>
<li><strong>SEO</strong> - Google prioriza sites acessíveis</li>
<li><strong>Reputação</strong> - Marca inclusiva</li>
<li><strong>Mercado</strong> - P público que você está excluindo</li>
</ol>
<hr>
<h2>WCAG 2.1 - Princípios</h2>

<h3>4 Princípios (POUR)</h3>

<figure class="wp-block-table"><table>
<tr><th>Princípio</th><th>Descrição</th></tr>
<tr><td><strong>Perceivable</strong></td><td>Informações devem ser perceptíveis</td></tr>
<tr><td><strong>Operable</strong></td><td>Interface deve ser operável</td></tr>
<tr><td><strong>Understandable</strong></td><td>Informações e interface compreensíveis</td></tr>
<tr><td><strong>Robust</strong></td><td>Conteúdo deve funcionar com tecnologias assistivas</td></tr>
</table></figure>

<h3>Níveis de Conformidade</h3>

<figure class="wp-block-table"><table>
<tr><th>Nível</th><th>Significado</th><th>Requisito</th></tr>
<tr><td><strong>A</strong></td><td>Básico</td><td>Mínimo, deve atender</td></tr>
<tr><td><strong>AA</strong></td><td>Padrão</td><td>Recomendado, maioria das leis</td></tr>
<tr><td><strong>AAA</strong></td><td>Avançado</td><td>Mais rigoroso, poucos достигают</td></tr>
</table></figure>

<hr>
<h2>Ferramentas Automatizadas</h2>

<h3>axe-core</h3>

<pre><code>// Npm
npm install @axe-core/playwright

<p>// Playwright integration<br>const { chromium } = require('playwright');<br>const AxeBuilder = require('@axe-core/playwright').default;</p>

<p>async function runAccessibilityTest() {<br>    const browser = await chromium.launch();<br>    const page = await browser.newPage();</p>

<p>await page.goto('https://example.com');</p>

<p>const results = await new AxeBuilder({ page })<br>        .withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])<br>        .analyze();</p>

<p>console.log('Violations:', results.violations.length);<br>    results.violations.forEach(v =&gt; {<br>        console.log(<code>- ${v.id}: ${v.description}</code>);<br>    });</p>

<p>await browser.close();<br>}<br></code></pre></p>

<h3>Lighthouse CI</h3>

<pre><code># GitHub Actions<ol><li>name: Lighthouse</li>
</ol>  uses: treosh/lighthouse-ci-action@v10
  with:
    urls: https://example.com
    budgetPath: ./lighthouserc.json
    uploadArtifacts: true
</code></pre>

<pre><code>// lighthouserc.json
{
  "ci": {
    "collect": {
      "settings": {
        "staticDistDir": "./dist"
      }
    },
    "assert": {
      "assertions": {
        "categories:accessibility": ["error", {"minScore": 0.9}],
        "first-contentful-paint": ["warn", { "maxNumericValue": 2000 }],
        "uses-passive-event-listeners": "off"
      }
    }
  }
}
</code></pre>

<hr>
<h2>Testes Manuais</h2>

<h3>Checklist de Teclado</h3>

<pre><code><h2>Navegação por Teclado</h2>

<h3>Essential</h3><ol><li>[ ] Tab avança logicamente entre elementos</li>
<li>[ ] Shift+Tab retorna ao elemento anterior</li>
<li>[ ] Enter ativa botões e links</li>
<li>[ ] Space ativa botões e checkboxes</li>
<li>[ ] Escape fecha modais e dropdowns</li>
<li>[ ] Setas navegam em menus</li>
</ol>
<h3>Skip Links</h3><ol><li>[ ] Link "Skip to main content" existe</li>
<li>[ ] Link é visível quando focado</li>
<li>[ ] Link funciona corretamente</li>
</ol>
<h3>Focus Indicators</h3><ol><li>[ ] Focus é sempre visível</li>
<li>[ ] Estilo de focus não é apenas cor</li>
<li>[ ] Focus não desaparece em nenhum elemento</li>
</ol></code></pre>

<h3>Checklist de Screen Reader</h3>

<pre><code><h2>Screen Reader Testing</h2>

<h3>Imagens</h3><ol><li>[ ] Alt text em todas imagens informativas</li>
<li>[ ] Alt text é descritivo e útil</li>
<li>[ ] Imagens decorativas têm alt=""</li>
<li>[ ] SVG complexos têm descriptions</li>
</ol>
<h3>Formulários</h3><ol><li>[ ] Labels associados corretamente (for/id)</li>
<li>[ ] Placeholder não substitui label</li>
<li>[ ] Erros anunciados</li>
<li>[ ] Required fields marcados</li>
</ol>
<h3>Heading Structure</h3><ol><li>[ ] h1 é único na página</li>
<li>[ ] Hierarquia lógica (h1 &gt; h2 &gt; h3)</li>
<li>[ ] Sem saltos (h1 &gt; h3, pulando h2)</li>
<li>[ ] Headings não são só visuais</li>
</ol>
<h3>Links e Botões</h3><ol><li>[ ] Links fazem sentido fora de contexto</li>
<li>[ ] Botões descrevem ação</li>
<li>[ ] Links novos/abrem em nova aba avisados</li></ol></ul>
</code></pre>

<hr>
<h2>Implementando Acessibilidade</h2>

<h3>ARIA Basics</h3>

<pre><code><!-- Botão com acessibilidade -->
<button aria-label="Fechar modal" aria-expanded="false" aria-controls="modal-content">
  <span aria-hidden="true">×</span>
</button>

<p><!-- Modal com ARIA --><br>&lt;div <br>  role="dialog" <br>  aria-labelledby="modal-title"<br>  aria-describedby="modal-desc"<br>  aria-modal="true"<br>&gt;<br>  <h2 id="modal-title">Confirmação</h2><br>  <p id="modal-desc">Tem certeza que deseja excluir?</p><br>  <button>Cancelar</button><br>  <button>Excluir</button><br></div></p>

<p><!-- Live region para updates --><br><div aria-live="polite"><br>  <!-- Conteúdo atualizado dinamicamente --><br></div></p>

<p><!-- Error message --><br><label for="email">Email</label><br><br><span id="email-error" class="error" role="alert"><br>  Email inválido<br></span><br></code></pre></p>

<h3>CSS para Acessibilidade</h3>

<pre><code>/<em> Focus visível </em>/
*:focus {
  outline: 3px solid #005fcc;
  outline-offset: 2px;
}

<p>/<em> Esconde visualmente mas mantém para screen readers </em>/<br>.sr-only {<br>  position: absolute;<br>  width: 1px;<br>  height: 1px;<br>  padding: 0;<br>  margin: -1px;<br>  overflow: hidden;<br>  clip: rect(0, 0, 0, 0);<br>  white-space: nowrap;<br>  border: 0;<br>}</p>

<p>/<em> Skip link </em>/<br>.skip-link {<br>  position: absolute;<br>  top: -40px;<br>  left: 0;<br>  background: #000;<br>  color: #fff;<br>  padding: 8px;<br>  z-index: 100;<br>}</p>

<p>.skip-link:focus {<br>  top: 0;<br>}</p>

<p>/<em> Contraste adequado </em>/<br>.text-primary {<br>  color: #1a1a1a; /<em> Não use #777777 com fundo branco </em>/<br>}</p>

<p>/<em> Touch target mínimo </em>/<br>button, a, input[type="checkbox"] {<br>  min-height: 44px;<br>  min-width: 44px;<br>}<br></code></pre></p>

<hr>
<h2>Conclusão</h2>

<p>Acessibilidade é responsabilidade de todos. As chaves são:<br><ol><li><strong>Testar cedo</strong> - A11y mais barato no início</li><br><li><strong>Automatizar</strong> - axe-core, Lighthouse</li><br><li><strong>Testar manualmente</strong> - Teclado, screen reader</li><br><li><strong>Seguir WCAG</strong> - 2.1 AA como mínimo</li><br><li><strong>Incluir na cultura</strong> - A11y não é "extra"</li></ol></p>