Documento técnico

Declaración de accesibilidad, criterio por criterio.

Autoevaluación sobre WCAG 2.2, niveles A y AA, con el método de cada comprobación. Su límite también está declarado, en el propio documento: falta la auditoría externa con lector de pantalla real, y hasta que se haga no afirmamos conformidad en ninguna página de esta web.

Producto: Sistema de Examen Virtual Universidad (plataforma web de exámenes con supervisión) Versión de la norma: WCAG 2.2, niveles A y AA Fecha de evaluación: 2026-07-24 (tercera ronda; segunda 2026-07-19, primera 2026-07-11) Método de evaluación: axe-core 4.12 en navegador real (@axe-core/playwright sobre Chromium) contra 20 escenarios — 11 rutas públicas, la portada en modo oscuro, 6 rutas autenticadas (docente, banco de preguntas, exámenes, acceso del alumno, panel del proctor y administración del tenant), las tres fases del runner del examen (verificación del sistema, vista de preguntas con los cuatro tipos de respuesta, y el diálogo de confirmación de entrega) y la vista de la segunda cámara en el teléfono (/movil/[token], antes y después de activar la cámara) — con las etiquetas wcag2a, wcag2aa, wcag21a, wcag21aa y wcag22aa, y umbral de cero violaciones serious/critical. Se suma a la revisión estática de todo el marcado (src/app/**, src/components/**), el cálculo de ratios de contraste sobre los tokens CSS, los E2E de flujo completo (Playwright/Chromium) y la suite de 900+ tests automatizados.

La medición se hace con prefers-reduced-motion: reduce, porque la web pública anima las entradas con animation-timeline: view() y sin eso axe evalúa el color de un fotograma intermedio en lugar del estado estable que exige el criterio 1.4.3.

Limitación declarada: no se han hecho pruebas con usuarios reales de tecnologías de asistencia. axe automatiza reglas —y por eso encontró lo que la revisión a ojo no veía— pero no sustituye a una persona navegando con NVDA o VoiceOver: se recomienda esa pasada antes de firmar un contrato que la exija. Las reglas automatizadas cubren aproximadamente un tercio de los criterios WCAG; el resto de esta declaración se sostiene en la revisión estática del marcado y en los E2E de flujo completo.

Estado global: Autoevaluación completada — se cumplen todos los criterios AA evaluados, con las salvedades documentadas abajo. La conformidad formal se declara tras una auditoría externa con tecnología de asistencia real, que aún no se ha realizado.

Resumen de conformidad por nivel

NivelCriteriosCumpleCumple parcialNo aplica
A302712
AA201910

Nivel A

CriterioEstadoObservaciones
1.1.1 Contenido no textualLas 2 <img> llevan alt (logo con alt del nombre de la institución); íconos lucide con aria-hidden; botones de solo ícono con aria-label; estados ✓/✗ con alternativa sr-only.
1.2.1 Solo audio / solo vídeo (pregrabado)➖ N/ANo hay contenido de audio/vídeo pregrabado.
1.2.2 Subtítulos (pregrabado)➖ N/AÍdem.
1.2.3 Audiodescripción o alternativa➖ N/AÍdem.
1.3.1 Información y relacionesfieldset/legend en opciones de respuesta; label htmlFor en todos los formularios; landmarks header/main; listas reales; headings jerárquicos corregidos.
1.3.2 Secuencia significativaDOM en orden lógico (verificado en runner y paneles).
1.3.3 Características sensorialesLas instrucciones no dependen de forma/posición/color.
1.4.1 Uso del colorTabs, chips, temporizador y severidades tienen indicador no cromático (subrayado, ícono, etiqueta textual).
1.4.2 Control de audio➖ N/ASin audio automático.
2.1.1 TecladoTodo operable por teclado (controles nativos + Radix); el lockdown no bloquea Tab/flechas.
2.1.2 Sin trampa de tecladoDiálogos Radix con foco atrapado intencional y salida por Esc.
2.1.4 Atajos de teclado de un carácterNo hay atajos de un carácter.
2.2.1 Tiempo ajustableEl límite del examen es esencial (excepción de la norma); además hay acomodaciones por alumno (factor 1.25×/1.5×/2× recalculado en servidor) desde batch5.
2.2.2 Pausar, detener, ocultarEl temporizador no parpadea; sin contenido en movimiento automático.
2.3.1 DestellosNada supera 3 destellos/segundo.
2.4.1 Evitar bloquesSkip link "Saltar al contenido principal" en el layout.
2.4.2 Página tituladatitle.template + metadata por página (incluida la de login).
2.4.3 Orden del focoGestión de foco al cambiar de pregunta y de fase en el runner.
2.4.4 Propósito del enlace (en contexto)Enlaces con texto descriptivo.
2.5.1 Gestos de punteroSin gestos multipunto ni basados en trayectoria.
2.5.2 Cancelación del punteroAcciones en click, no en down.
2.5.3 Etiqueta en el nombreNombres accesibles coinciden con el texto visible.
2.5.4 Activación por movimientoNada se activa por movimiento del dispositivo.
3.1.1 Idioma de la páginalang="es".
3.2.1 Al recibir el focoSin cambios de contexto al enfocar.
3.2.2 Al introducir datosSin cambios de contexto al escribir (autoguardado silencioso).
3.2.6 Ayuda consistenteNavegación y acciones consistentes entre vistas.
3.3.1 Identificación de erroresaria-invalid + aria-describedby + role="alert" en formularios.
3.3.2 Etiquetas o instruccionesTodos los campos con label asociado; las respuestas del examen con aria-labelledby al enunciado.
3.3.7 Entrada redundanteNo se pide dos veces la misma información.

Nivel AA

CriterioEstadoObservaciones
1.2.4 Subtítulos (en vivo)➖ N/ASin contenido en vivo.
1.2.5 Audiodescripción➖ N/AÍdem.
1.3.4 OrientaciónSin bloqueo de orientación de pantalla.
1.3.5 Identificar propósito de entradaautoComplete en login y formularios de alta.
1.4.3 Contraste mínimoTokens de estado rehechos con pares texto/fondo medidos ≥4.5:1; white-label deriva --primary-foreground por luminancia; muted-foreground oscurecido. Verificado con axe en las 18 rutas auditadas (2026-07-24), que encontró 4 incumplimientos que la revisión estática no podía detectar —el color resuelto con opacidad y herencia no se ve leyendo el marcado— y quedaron corregidos: --medida daba 4,33:1 sobre el papel (ahora 4,94:1); los tokens -vivo, calibrados para superficies oscuras, se usaban como texto sobre papel con 2,0:1 y 2,39:1; un párrafo con opacidad sobre índigo daba 4,46:1; y el índigo pleno como texto sobre tinta, 3,01:1. Los tres últimos se resolvieron con tokens (--medida-texto, --cautela-texto, --indigo-texto) que el CSS resuelve según la superficie.
1.4.4 Redimensionar textoZoom al 200 % operativo y la heurística anti-DevTools ya no sanciona el zoom (degradada a evidencia; bug A-01 corregido).
1.4.5 Imágenes de textoSin imágenes de texto.
1.4.10 ReflujoFilas de resultados con flex-wrap; sin scroll horizontal a 320 px.
1.4.11 Contraste no textualAnillo de foco focus-visible con contraste ≥3:1; estados de controles no dependen del color.
1.4.12 Espaciado de textoSin contenedores de altura fija que recorten al aumentar el espaciado.
1.4.13 Contenido al pasar o enfocarSin popups personalizados de hover/focus.
2.4.5 Múltiples víasNavegación por secciones y listados; breadcrumbs implícitos en títulos.
2.4.6 Encabezados y etiquetasEncabezados descriptivos por vista.
2.4.7 Foco visibleAnillo compartido focus-visible en botones/inputs/tabs/chips.
2.4.11 Foco no oculto (mínimo)El overlay de proctoring es colapsable y no cubre el elemento enfocado en escritorio.
2.5.7 Movimientos de arrastreSin interacciones de arrastre.
2.5.8 Tamaño del objetivo (mínimo)Objetivos ≥24 px CSS (opciones de respuesta con p-3, muy por encima).
3.1.2 Idioma de las partesContenido en español uniforme (anglicismos del dominio eliminados).
3.2.3 Navegación consistenteShell de navegación único (DashboardShell).
3.2.4 Identificación consistenteMismos íconos/etiquetas para las mismas acciones.
3.3.3 Sugerencia ante erroresErrores con mensaje accionable (no "Error 500" pelado).
3.3.4 Prevención de errores (legal/financiero/datos)La entrega del examen exige confirmación con resumen de sin-responder (Radix AlertDialog con foco atrapado).
3.3.8 Autenticación accesibleLogin email+contraseña sin rompecabezas cognitivos ni pruebas de memoria.
4.1.3 Mensajes de estadorole="alert"/aria-live en errores, avisos de strikes, estado offline, "respondidas X/Y" y panel del proctor.

Salvedades declaradas (cumplimiento parcial)

  • 1.3.1 / tablas de datos (parcial): los listados principales usan listas semánticas; si una vista futura introduce tablas de datos complejas, deberá usar th scope antes de declararse.
  • 2.4.11 Foco no oculto (parcial en pantallas <640 px): el overlay de proctoring puede tapar controles en pantallas muy pequeñas; es colapsable y el examen sigue operable, pero se recomienda rendir en pantalla ≥1024 px (documentado al alumno).
  • Alcance de la auditoría automatizada: cubre todas las vistas del producto. El runner del examen entró el 2026-07-24 (verificación del sistema, preguntas y diálogo de entrega) y la segunda cámara en el teléfono (/movil/[token]) el 2026-07-25, auditada en sus dos estados —antes de activar la cámara y transmitiendo—, ambas con cero violaciones serious/critical a la primera pasada. Ya no queda ninguna pantalla fuera del alcance automatizado.

Funciones de acomodación (más allá de la norma)

  • Tiempo extra por alumno (1.25×/1.5×/2×) fijado por el docente por sesión, recalculado en el servidor y auditado (batch5).
  • Exención de avisos automáticos por alumno: los eventos de bloqueo (foco/pegar/pestaña) se registran como evidencia sin sanción automática, para tecnologías de asistencia.
  • El zoom del navegador nunca genera sanción (la heurística de DevTools es solo evidencia).
  • Temporizador con avisos textuales además del color; mensajes de estado anunciados por lector de pantalla.

Esta declaración se basa en la evidencia de audit/05-uxui-a11y.md, audit/ronda2/REPORTE.md y audit/loop/ESTADO.md (tercera ronda). La auditoría automatizada es reproducible: npx playwright test tests/e2e/accesibilidad.spec.ts. Regenerar si cambian el flujo de examen, los tokens de color o el sistema de avisos.

tests/unit/vpat.test.ts vigila que este documento no se desalinee de la cobertura real: si axe empieza a auditar el runner, o deja de hacerlo, el test obliga a corregir la declaración en lugar de dejarla envejecer.