Informe de Auditoría WCAG 2.2

Análisis completo de accesibilidad web — principios POUR · niveles A, AA, AAA
GreenMind SaaS B2B
16 junio 2026 · Auditor: CULTIVA IA
OBJETIVO: WCAG 2.2 NIVEL AA
Críticas
5
Bloqueantes — acceso imposible
Serias
8
Acceso muy difícil
Moderadas
11
Fricción significativa
Conformes
31
Criterios superados
50% NO CONFORME

Estado actual: Nivel AA incompleto

GreenMind cumple el 50% de los criterios WCAG 2.2 AA auditados. Se detectaron 24 violaciones en 4 módulos del producto. Las 5 violaciones críticas bloquean completamente el acceso a usuarios con discapacidad motora, visual y cognitiva, e impiden alcanzar el nivel A mínimo.

Onboarding / Signup Dashboard principal Formulario de empresa Módulo de informes Menú de navegación Modal de configuración
Resumen por principios POUR
👁️
Perceptible
9 violaciones · 3 críticas
⌨️
Operable
7 violaciones · 2 críticas
🧠
Comprensible
5 violaciones · 0 críticas
🔧
Robusto
3 violaciones · 0 críticas
Violaciones críticas — requieren acción inmediata
Crítica A Botones de acción sin texto accesible (icono puro) Perceptible 1.1.1 · 4.1.2

Ubicación y evidencia

Dashboard principal → barra de acciones (botones exportar, filtrar, configurar). 12 botones con solo icono SVG sin aria-label ni texto visible.

<!-- ❌ Incorrecto -->
<button class="icon-btn">
  <svg>...icono-engranaje...</svg>
</button>
  • Lectores de pantalla (NVDA, VoiceOver): leen "botón" sin nombre
  • Usuarios con baja visión: sin referencia semántica
  • Control por voz (Dragon): no pueden activar el elemento

Remediación

Añadir aria-label descriptivo a cada botón. Alternativa: texto visualmente oculto con clase .sr-only.

<!-- ✅ Correcto — aria-label -->
<button class="icon-btn"
        aria-label="Exportar informe a PDF">
  <svg aria-hidden="true">...</svg>
</button>

<!-- ✅ Correcto — texto oculto -->
<button class="icon-btn">
  <svg aria-hidden="true">...</svg>
  <span class="sr-only">Exportar PDF</span>
</button>

/* CSS .sr-only */
.sr-only { position:absolute; width:1px;
  height:1px; clip:rect(0,0,0,0);
  overflow:hidden; white-space:nowrap; }

⏱ Esfuerzo: 2h · Impacto: bloquea usuarios con lector de pantalla

Crítica A Formulario de alta sin etiquetas en 14 de 20 campos Perceptible 1.3.1 · 3.3.2

Ubicación y evidencia

Formulario de alta empresa → 14 campos usan solo placeholder como etiqueta. Al recibir foco, el placeholder desaparece y el usuario pierde el contexto del campo.

<!-- ❌ Incorrecto -->
<input type="email"
  placeholder="correo@empresa.com" />

<input type="tel"
  placeholder="Teléfono de contacto" />

Remediación

<!-- ✅ Correcto — label visible -->
<label for="email-empresa">
  Correo electrónico
  <span aria-hidden="true">*</span>
  <span class="sr-only">(obligatorio)</span>
</label>
<input id="email-empresa"
  type="email"
  autocomplete="email"
  aria-required="true"
  placeholder="correo@empresa.com" />

⏱ Esfuerzo: 4h · Impacto: bloquea usuarios con lector de pantalla y cognitivos

Crítica A Gráficas de emisiones sin alternativa textual Perceptible 1.1.1

Ubicación y evidencia

Dashboard → 6 gráficas Chart.js renderizadas en <canvas> sin descripción alternativa. Los datos son inaccesibles para usuarios de lector de pantalla.

<!-- ❌ Incorrecto -->
<canvas id="emissions-chart"
  width="600" height="300">
</canvas>

Remediación

<!-- ✅ Correcto -->
<canvas id="emissions-chart"
  role="img"
  aria-label="Evolución emisiones CO₂:
    Ene 12t, Feb 11t, Mar 9t, Abr 8t">
  <!-- Tabla de datos de respaldo -->
  <table>
    <caption>Emisiones mensuales CO₂</caption>
    <tr><th>Mes</th><th>Toneladas</th></tr>
    <tr><td>Enero</td><td>12</td></tr>
    ...
  </table>
</canvas>

⏱ Esfuerzo: 6h · Impacto: datos principales inaccesibles

Crítica A Trampa de teclado en modal de configuración Operable 2.1.2

Ubicación y evidencia

Modal de configuración de empresa → al navegar con Tab, el foco sale del modal y llega a elementos del fondo. Esc no cierra el diálogo. Usuario de teclado queda atrapado.

  • Usuarios que navegan solo con teclado
  • Usuarios de switch access
  • Usuarios con temblor (no pueden usar ratón)

Remediación

// Focus trap + Esc handler
function trapFocus(modal) {
  const focusable = modal.querySelectorAll(
    'a,button,input,select,textarea,[tabindex]:not([tabindex="-1"])'
  );
  const first = focusable[0];
  const last  = focusable[focusable.length-1];

  modal.addEventListener('keydown', e => {
    if (e.key === 'Escape') closeModal();
    if (e.key === 'Tab') {
      if (e.shiftKey && doc.activeElement===first)
        { last.focus(); e.preventDefault(); }
      else if (!e.shiftKey && doc.activeElement===last)
        { first.focus(); e.preventDefault(); }
    }
  });
  first.focus();
}

⏱ Esfuerzo: 3h · Impacto: bloquea navegación completa por teclado

Crítica A Errores de formulario no vinculados al campo ni anunciados Comprensible 3.3.1

Ubicación y evidencia

Al enviar formulario de alta con errores, se muestra un banner genérico "Hay errores en el formulario" sin indicar qué campo falló ni ofrecer corrección. Los mensajes de error no están vinculados programáticamente al input.

<!-- ❌ Incorrecto -->
<div class="error-banner">
  Hay errores en el formulario
</div>
<input type="email" class="error" />
<!-- el campo no sabe que tiene error -->

Remediación

<!-- ✅ Correcto -->
<label for="email">Email corporativo</label>
<input id="email" type="email"
  aria-invalid="true"
  aria-describedby="email-err" />
<span id="email-err" role="alert"
  class="field-error">
  Introduce un email válido
  (ej: nombre@empresa.com)
</span>

/* Mover foco al primer campo con error */
document.querySelector('[aria-invalid]')
  ?.focus();

⏱ Esfuerzo: 3h · Impacto: usuarios cognitivos y lector de pantalla no pueden corregir

Violaciones serias (8) — resumen ejecutivo
Violación Criterio Nivel Esfuerzo
Verde #4CAF50 sobre blanco: ratio 3.1:1 (requiere 4.5:1 en texto normal) 1.4.3 AA 2h
Sin enlace "Saltar al contenido principal" en ninguna página 2.4.1 A 1h
Títulos de página duplicados en todas las vistas del dashboard 2.4.2 A 1h
Indicador de foco CSS eliminado con outline:none global 2.4.7 2.4.11 AA 2h
Widget de selector de rango de fechas no operable con teclado 2.1.1 A 8h
Animación de carga continua sin respetar prefers-reduced-motion 2.2.2 A 1h
Tabla de datos sin <th scope> ni <caption> 1.3.1 A 3h
Mensajes de estado del sistema sin role="status" / live region 4.1.3 AA 2h
Plan de remediación — 6 semanas
Semanas 1-2
Críticas bloqueantes
  • aria-label en 12 botones de icono
  • Labels visibles en formulario de empresa
  • Focus trap en modal de configuración
  • Errores vinculados con aria-describedby
  • Alt text en gráficas canvas
Semanas 3-4
Serias de alta prioridad
  • Corregir contraste verde #4CAF50 → #3d8b3d
  • Añadir skip link en todas las páginas
  • Títulos de página únicos por vista
  • Restablecer estilos de foco (outline)
  • prefers-reduced-motion en animaciones
Semanas 5-6
Moderadas + validación final
  • Datepicker accesible por teclado
  • Tabla con th scope + caption
  • Live regions para mensajes de estado
  • Jerarquía de encabezados h1-h6
  • Test con NVDA + VoiceOver real
Herramientas de testing recomendadas
Herramienta Tipo Uso Cobertura Coste
axe DevTools Automático Extensión Chrome/Firefox — escaneo en tiempo real ~30-40% criterios Gratis
WAVE Automático Overlay visual de errores en la página ~25% criterios Gratis
Lighthouse Automático Auditoría integrada en Chrome DevTools ~20% criterios Gratis
NVDA + Firefox Manual Lector de pantalla Windows — pruebas con usuario real Flujos completos Gratis
VoiceOver + Safari Manual Lector de pantalla macOS/iOS Flujos completos Gratis
axe-core + Playwright Automático CI/CD — test de regresión de accesibilidad 30-40% criterios Gratis
WebAIM Contrast Checker Manual Validación de ratios de contraste Criterio 1.4.3 Gratis