본문으로 건너뛰기
cccskills
무료GitHub에 공개

accessibility

Auditar e melhorar a acessibilidade web seguindo as diretrizes WCAG 2.1. Use quando solicitado para "melhorar acessibilidade", "auditoria a11y", "conformidade WCAG", "suporte a leitor de tela", "navegação por teclado" ou "tornar acessível".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(2)

  • SKILL.md12.9 KB
  • references/WCAG.md7.2 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Acessibilidade (a11y)

Diretrizes abrangentes de acessibilidade baseadas em WCAG 2.1 e auditorias de acessibilidade do Lighthouse. Objetivo: tornar o conteúdo utilizável por todos, incluindo pessoas com deficiências.

Princípios WCAG: POUR

PrincípioDescrição
PerceptívelO conteúdo pode ser percebido através de diferentes sentidos
OperávelA interface pode ser operada por todos os usuários
CompreensívelO conteúdo e a interface são compreensíveis
RobustoO conteúdo funciona com tecnologias assistivas

Níveis de conformidade

NívelRequisitoAlvo
AAcessibilidade mínimaDeve passar
AAConformidade padrãoDeve passar (exigência legal em muitas jurisdições)
AAAAcessibilidade aprimoradaDesejável

Perceptível

Alternativas de texto (1.1)

Imagens exigem texto alternativo:

<!-- ❌ Alt ausente -->
<img src="chart.png">

<!-- ✅ Alt descritivo -->
<img src="chart.png" alt="Gráfico de barras mostrando aumento de 40% nas vendas do Q3">

<!-- ✅ Imagem decorativa (alt vazio) -->
<img src="decorative-border.png" alt="" role="presentation">

<!-- ✅ Imagem complexa com descrição mais longa -->
<figure>
  <img src="infographic.png" alt="Infográfico de tendências de mercado 2024" 
       aria-describedby="infographic-desc">
  <figcaption id="infographic-desc">
    <!-- Descrição detalhada -->
  </figcaption>
</figure>

Botões com ícones precisam de nomes acessíveis:

<!-- ❌ Sem nome acessível -->
<button><svg><!-- menu icon --></svg></button>

<!-- ✅ Usando aria-label -->
<button aria-label="Abrir menu">
  <svg aria-hidden="true"><!-- menu icon --></svg>
</button>

<!-- ✅ Usando texto visualmente oculto -->
<button>
  <svg aria-hidden="true"><!-- menu icon --></svg>
  <span class="visually-hidden">Abrir menu</span>
</button>

Classe de texto visualmente oculto:

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

Contraste de cor (1.4.3, 1.4.6)

Tamanho de textoAA mínimoAAA aprimorado
Texto normal (< 18px / < 14px negrito)4.5:17:1
Texto grande (≥ 18px / ≥ 14px negrito)3:14.5:1
Componentes de UI e gráficos3:13:1
/* ❌ Contraste baixo (2.5:1) */
.low-contrast {
  color: #999;
  background: #fff;
}

/* ✅ Contraste suficiente (7:1) */
.high-contrast {
  color: #333;
  background: #fff;
}

/* ✅ Estados de foco precisam de contraste também */
:focus-visible {
  outline: 2px solid #005fcc;
  outline-offset: 2px;
}

Não dependa apenas de cor:

<!-- ❌ Apenas cor indica erro -->
<input class="error-border">
<style>.error-border { border-color: red; }</style>

<!-- ✅ Cor + ícone + texto -->
<div class="field-error">
  <input aria-invalid="true" aria-describedby="email-error">
  <span id="email-error" class="error-message">
    <svg aria-hidden="true"><!-- error icon --></svg>
    Por favor, insira um endereço de email válido
  </span>
</div>

Alternativas para mídia (1.2)

<!-- Vídeo com legendas -->
<video controls>
  <source src="video.mp4" type="video/mp4">
  <track kind="captions" src="captions.vtt" srclang="pt" label="Português" default>
  <track kind="descriptions" src="descriptions.vtt" srclang="pt" label="Descrições">
</video>

<!-- Áudio com transcrição -->
<audio controls>
  <source src="podcast.mp3" type="audio/mp3">
</audio>
<details>
  <summary>Transcrição</summary>
  <p>Texto completo da transcrição...</p>
</details>

Operável

Acessível por teclado (2.1)

Toda funcionalidade deve ser acessível por teclado:

// ❌ Apenas manipula click
element.addEventListener('click', handleAction);

// ✅ Manipula click e teclado
element.addEventListener('click', handleAction);
element.addEventListener('keydown', (e) => {
  if (e.key === 'Enter' || e.key === ' ') {
    e.preventDefault();
    handleAction();
  }
});

Sem armadilhas de teclado:

// Gerenciamento de foco do modal
function openModal(modal) {
  const focusableElements = modal.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const firstElement = focusableElements[0];
  const lastElement = focusableElements[focusableElements.length - 1];
  
  // Prender foco dentro do modal
  modal.addEventListener('keydown', (e) => {
    if (e.key === 'Tab') {
      if (e.shiftKey && document.activeElement === firstElement) {
        e.preventDefault();
        lastElement.focus();
      } else if (!e.shiftKey && document.activeElement === lastElement) {
        e.preventDefault();
        firstElement.focus();
      }
    }
    if (e.key === 'Escape') {
      closeModal();
    }
  });
  
  firstElement.focus();
}

Foco visível (2.4.7)

/* ❌ Nunca remova contornos de foco */
*:focus { outline: none; }

/* ✅ Use :focus-visible para foco apenas por teclado */
:focus {
  outline: none;
}

:focus-visible {
  outline: 2px solid #005fcc;
  outline-offset: 2px;
}

/* ✅ Ou estilos de foco personalizados */
button:focus-visible {
  box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);
}

Links para pular (2.4.1)

<body>
  <a href="#main-content" class="skip-link">Pular para conteúdo principal</a>
  <header><!-- navigation --></header>
  <main id="main-content" tabindex="-1">
    <!-- main content -->
  </main>
</body>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px 16px;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}

Timing (2.2)

// Permita que usuários estendam limites de tempo
function showSessionWarning() {
  const modal = createModal({
    title: 'Sessão expirando',
    content: 'Sua sessão expirará em 2 minutos.',
    actions: [
      { label: 'Estender sessão', action: extendSession },
      { label: 'Sair', action: logout }
    ],
    timeout: 120000 // 2 minutos para responder
  });
}

Movimento (2.3)

/* Respeite a preferência de movimento reduzido */
@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;
  }
}

Compreensível

Idioma da página (3.1.1)

<!-- ❌ Sem idioma especificado -->
<html>

<!-- ✅ Idioma especificado -->
<html lang="pt-BR">

<!-- ✅ Mudanças de idioma dentro da página -->
<p>A palavra em inglês para olá é <span lang="en">hello</span>.</p>

Navegação consistente (3.2.3)

<!-- A navegação deve ser consistente entre páginas -->
<nav aria-label="Principal">
  <ul>
    <li><a href="/" aria-current="page">Início</a></li>
    <li><a href="/products">Produtos</a></li>
    <li><a href="/about">Sobre</a></li>
  </ul>
</nav>

Rótulos de formulário (3.3.2)

<!-- ❌ Sem associação de rótulo -->
<input type="email" placeholder="Email">

<!-- ✅ Rótulo explícito -->
<label for="email">Endereço de email</label>
<input type="email" id="email" name="email" 
       autocomplete="email" required>

<!-- ✅ Rótulo implícito -->
<label>
  Endereço de email
  <input type="email" name="email" autocomplete="email" required>
</label>

<!-- ✅ Com instruções -->
<label for="password">Senha</label>
<input type="password" id="password" 
       aria-describedby="password-requirements">
<p id="password-requirements">
  Deve ter pelo menos 8 caracteres com um número.
</p>

Tratamento de erros (3.3.1, 3.3.3)

<!-- Anuncie erros para leitores de tela -->
<form novalidate>
  <div class="field" aria-live="polite">
    <label for="email">Email</label>
    <input type="email" id="email" 
           aria-invalid="true"
           aria-describedby="email-error">
    <p id="email-error" class="error" role="alert">
      Por favor, insira um endereço de email válido (ex: nome@exemplo.com)
    </p>
  </div>
</form>
// Foque no primeiro erro ao enviar
form.addEventListener('submit', (e) => {
  const firstError = form.querySelector('[aria-invalid="true"]');
  if (firstError) {
    e.preventDefault();
    firstError.focus();
    
    // Anuncie resumo de erro
    const errorSummary = document.getElementById('error-summary');
    errorSummary.textContent = `${errors.length} erros encontrados. Por favor, corrija-os e tente novamente.`;
    errorSummary.focus();
  }
});

Robusto

HTML válido (4.1.1)

<!-- ❌ IDs duplicados -->
<div id="content">...</div>
<div id="content">...</div>

<!-- ❌ Aninhamento inválido -->
<a href="/"><button>Clique</button></a>

<!-- ✅ IDs únicos -->
<div id="main-content">...</div>
<div id="sidebar-content">...</div>

<!-- ✅ Aninhamento apropriado -->
<a href="/" class="button-link">Clique</a>

Uso de ARIA (4.1.2)

Prefira elementos nativos:

<!-- ❌ Função ARIA em div -->
<div role="button" tabindex="0">Clique</div>

<!-- ✅ Botão nativo -->
<button>Clique</button>

<!-- ❌ Caixa de seleção ARIA -->
<div role="checkbox" aria-checked="false">Opção</div>

<!-- ✅ Caixa de seleção nativa -->
<label><input type="checkbox"> Opção</label>

Quando ARIA é necessária:

<!-- Componente de abas personalizado -->
<div role="tablist" aria-label="Informações do produto">
  <button role="tab" id="tab-1" aria-selected="true" 
          aria-controls="panel-1">Descrição</button>
  <button role="tab" id="tab-2" aria-selected="false" 
          aria-controls="panel-2" tabindex="-1">Avaliações</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
  <!-- Conteúdo do painel -->
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
  <!-- Conteúdo do painel -->
</div>

Regiões dinâmicas (4.1.3)

<!-- Atualizações de status -->
<div aria-live="polite" aria-atomic="true" class="status">
  <!-- O conteúdo atualizado é anunciado para leitores de tela -->
</div>

<!-- Alertas urgentes -->
<div role="alert" aria-live="assertive">
  <!-- Interrompe o anúncio atual -->
</div>
// Anuncie mudanças de conteúdo dinâmico
function showNotification(message, type = 'polite') {
  const container = document.getElementById(`${type}-announcer`);
  container.textContent = ''; // Limpe primeiro
  requestAnimationFrame(() => {
    container.textContent = message;
  });
}

Checklist de testes

Testes automatizados

# Auditoria de acessibilidade do Lighthouse
npx lighthouse https://example.com --only-categories=accessibility

# axe-core
npm install @axe-core/cli -g
axe https://example.com

Testes manuais

  • Navegação por teclado: Tab em toda a página, use Enter/Space para ativar
  • Leitor de tela: Teste com VoiceOver (Mac), NVDA (Windows) ou TalkBack (Android)
  • Zoom: Conteúdo utilizável com zoom de 200%
  • Contraste alto: Teste com Modo de Contraste Alto do Windows
  • Movimento reduzido: Teste com prefers-reduced-motion: reduce
  • Ordem de foco: Lógica e segue a ordem visual

Comandos do leitor de tela

AçãoVoiceOver (Mac)NVDA (Windows)
Iniciar/Parar⌘ + F5Ctrl + Alt + N
Próximo itemVO + →↓
Item anteriorVO + ←↑
AtivarVO + SpaceEnter
Lista de headingsVO + U, depois setasH / Shift + H
Lista de linksVO + UK / Shift + K

Problemas comuns por impacto

Críticos (corrigir imediatamente)

  1. Rótulos de formulário ausentes
  2. Texto alternativo de imagem ausente
  3. Contraste de cor insuficiente
  4. Armadilhas de teclado
  5. Sem indicadores de foco

Sérios (corrigir antes do lançamento)

  1. Idioma da página ausente
  2. Estrutura de heading ausente
  3. Texto de link não descritivo
  4. Mídia reproduzida automaticamente
  5. Links para pular ausentes

Moderados (corrigir em breve)

  1. Rótulos ARIA ausentes em ícones
  2. Navegação inconsistente
  3. Identificação de erro ausente
  4. Timing sem controles
  5. Regiões landmark ausentes

Referências

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Especialista em construir experiências 3D para a web - Three.js, React Three Fiber, Spline, WebGL e cenas 3D interativas. Cobre configuradores de produtos, portfólios 3D, websites imersivos e adição de profundidade às experiências web. Use quando: website 3D, three.js, WebGL, react three fiber, experiência 3D.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

artubss/SKILLS-CLAUDE-CODE112026년 5월 17일 업데이트

Quando o usuário quer planejar, projetar ou implementar um teste A/B ou experimento. Também use quando o usuário menciona "teste A/B", "split test", "experimento", "testar essa mudança", "copy variante", "teste multivariado" ou "hipótese". Para implementação de rastreamento, veja analytics-tracking.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

artubss/SKILLS-CLAUDE-CODE112026년 5월 17일 업데이트

Testes e benchmarking de agentes LLM incluindo testes comportamentais, avaliação de capacidades, métricas de confiabilidade e monitoramento em produção—onde até os melhores agentes alcançam menos de 50% em benchmarks do mundo real. Use quando: testes de agentes, avaliação de agentes, benchmark de agentes, confiabilidade de agentes, teste de agentes.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

artubss/SKILLS-CLAUDE-CODE112026년 5월 17일 업데이트

Criar, gerenciar e orquestrar agentes de IA usando o CLI AI Maestro. Use quando o usuário pedir para "criar agente", "listar agentes", "deletar agente", "hibernar agente", "despertar agente", "instalar plugin", "mostrar agente", "reiniciar agente" ou qualquer tarefa de gerenciamento do ciclo de vida do agente.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

artubss/SKILLS-CLAUDE-CODE112026년 5월 17일 업데이트

Gerencie múltiplos agentes CLI locais via sessões tmux (iniciar/parar/monitorar/atribuir) com agendamento compatível com cron.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

artubss/SKILLS-CLAUDE-CODE112026년 5월 17일 업데이트

Refatore arquivos de instruções de agentes AGENTS.md, CLAUDE.md ou similares para seguir princípios de divulgação progressiva. Divide arquivos monolíticos em documentação organizada e vinculada.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

artubss/SKILLS-CLAUDE-CODE112026년 5월 17일 업데이트

artubss의 스킬 모두 보기

이 스킬의 문제 신고