Saltar al catálogo

Consulta gratuita

Catálogo WCAG 2.2 en español

Los 55 criterios de conformidad de nivel A y AA, con descripción, cómo verificarlos y ejemplos de código. La referencia base para cumplir la Ley 7600, ADA y Section 508.

Criterios A + AA
55
Nivel A
31
Nivel AA
24
Nuevos en 2.2
6

Buscador de criterios

55 de 55 criterios

  • 1.1.1Contenido no textualNivel APerceptibleAutomatizable

    Todo contenido no textual que se presenta al usuario tiene una alternativa textual que cumple el mismo propósito.

    Cómo verificarlo

    • Inspeccionar todas las imágenes y verificar que tengan atributo alt
    • Verificar que el texto alternativo describe el propósito de la imagen
    • Para imágenes decorativas, verificar que alt esté vacío (alt='')
    • Verificar que los controles de formulario tengan etiquetas asociadas

    Correcto

    <!-- Imagen informativa -->
    <img src="logo.png" alt="Empresa XYZ - Soluciones de accesibilidad">
    
    <!-- Imagen decorativa -->
    <img src="decoracion.png" alt="" role="presentation">
    
    <!-- Botón con icono -->
    <button aria-label="Cerrar ventana">
      <svg>...</svg>
    </button>

    Incorrecto

    <!-- Sin texto alternativo -->
    <img src="logo.png">
    
    <!-- Texto alternativo genérico -->
    <img src="grafico.png" alt="imagen">
    
    <!-- Botón sin etiqueta -->
    <button>
      <svg>...</svg>
    </button>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.2.1Solo audio y solo video (grabado)Nivel APerceptibleManual

    Para medios pregrabados de solo audio y solo video, se proporciona una alternativa para medios tempodependientes o una pista de audio.

    Cómo verificarlo

    • Identificar todos los elementos de audio y video pregrabados
    • Verificar que exista una transcripción textual para contenido de solo audio
    • Verificar que exista una descripción textual o audio descripción para contenido de solo video
    • Confirmar que las alternativas transmiten la misma información

    Correcto

    <audio controls>
      <source src="podcast.mp3" type="audio/mpeg">
    </audio>
    <details>
      <summary>Transcripción del audio</summary>
      <p>En este episodio discutimos...</p>
    </details>

    Incorrecto

    <audio controls>
      <source src="podcast.mp3" type="audio/mpeg">
    </audio>
    <!-- Sin transcripción -->
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.2.2Subtítulos (grabados)Nivel APerceptibleManual

    Se proporcionan subtítulos para todo el contenido de audio pregrabado en medios sincronizados.

    Cómo verificarlo

    • Reproducir todos los videos con audio
    • Verificar que existan subtítulos disponibles
    • Confirmar que los subtítulos incluyen diálogos y sonidos importantes
    • Verificar que los subtítulos estén sincronizados con el audio

    Correcto

    <video controls>
      <source src="video.mp4" type="video/mp4">
      <track kind="captions" src="subtitulos-es.vtt" srclang="es" label="Español">
      <track kind="captions" src="subtitles-en.vtt" srclang="en" label="English">
    </video>

    Incorrecto

    <video controls>
      <source src="video.mp4" type="video/mp4">
    </video>
    <!-- Sin subtítulos -->
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.2.3Audiodescripción o medio alternativo (grabado)Nivel APerceptibleManual

    Se proporciona una alternativa para medios tempodependientes o una audiodescripción del contenido de video pregrabado.

    Cómo verificarlo

    • Identificar videos pregrabados con información visual importante
    • Verificar que exista audiodescripción o transcripción descriptiva
    • Confirmar que la audiodescripción describe acciones, personajes, cambios de escena
    • Verificar que la información visual esencial esté disponible en formato alternativo

    Correcto

    <video controls>
      <source src="video.mp4" type="video/mp4">
      <track kind="descriptions" src="audiodesc-es.vtt" srclang="es" label="Audiodescripción">
    </video>
    
    <!-- O proporcionar transcripción descriptiva -->
    <details>
      <summary>Transcripción descriptiva</summary>
      <p>[Escena: Oficina moderna. Juan entra por la puerta...]</p>
    </details>

    Incorrecto

    <video controls>
      <source src="video.mp4" type="video/mp4">
    </video>
    <!-- Sin audiodescripción ni alternativa -->
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.2.4Subtítulos (en directo)Nivel AAPerceptibleManual

    Se proporcionan subtítulos para todo el contenido de audio en directo en medios sincronizados.

    Cómo verificarlo

    • Identificar contenido de video en vivo con audio
    • Verificar que existan subtítulos en tiempo real
    • Confirmar que los subtítulos capturan diálogos y sonidos importantes
    • Verificar la precisión y sincronización de los subtítulos en vivo

    Correcto

    <!-- Usar servicios de subtitulado en vivo -->
    <iframe src="https://streaming.example.com/live?captions=true"></iframe>
    
    <!-- O integrar servicio de subtitulado -->
    <div class="live-stream">
      <video id="live-video" controls></video>
      <div id="live-captions" aria-live="polite"></div>
    </div>

    Incorrecto

    <iframe src="https://streaming.example.com/live"></iframe>
    <!-- Sin subtítulos en vivo -->
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.2.5Audiodescripción (grabada)Nivel AAPerceptibleManual

    Se proporciona audiodescripción para todo el contenido de video pregrabado en medios sincronizados.

    Cómo verificarlo

    • Reproducir todos los videos pregrabados
    • Verificar que exista pista de audiodescripción disponible
    • Confirmar que describe información visual importante
    • Verificar que la audiodescripción no interfiere con el audio principal

    Correcto

    <video controls>
      <source src="video.mp4" type="video/mp4">
      <track kind="descriptions" src="audiodesc.vtt" srclang="es" label="Audiodescripción">
    </video>

    Incorrecto

    <video controls>
      <source src="video.mp4" type="video/mp4">
    </video>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.3.1Información y relacionesNivel APerceptibleAutomatizable

    La información, estructura y relaciones transmitidas a través de la presentación pueden ser determinadas por software o están disponibles en texto.

    Cómo verificarlo

    • Inspeccionar el código HTML para verificar uso semántico correcto
    • Verificar que los encabezados usen elementos <h1>-<h6> apropiados
    • Confirmar que las listas usen <ul>, <ol>, <li>
    • Verificar que las tablas de datos usen <table>, <th>, <td> con scope apropiado
    • Confirmar que los formularios tengan <label> asociados correctamente

    Correcto

    <!-- Estructura semántica -->
    <article>
      <h1>Título principal</h1>
      <section>
        <h2>Sección 1</h2>
        <p>Contenido...</p>
      </section>
    </article>
    
    <!-- Lista semántica -->
    <ul>
      <li>Elemento 1</li>
      <li>Elemento 2</li>
    </ul>
    
    <!-- Tabla de datos -->
    <table>
      <thead>
        <tr>
          <th scope="col">Nombre</th>
          <th scope="col">Edad</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Juan</td>
          <td>30</td>
        </tr>
      </tbody>
    </table>

    Incorrecto

    <!-- Sin semántica -->
    <div class="title">Título principal</div>
    <div class="section">
      <div class="subtitle">Sección 1</div>
      <div>Contenido...</div>
    </div>
    
    <!-- Lista con divs -->
    <div class="list">
      <div>Elemento 1</div>
      <div>Elemento 2</div>
    </div>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.3.2Secuencia significativaNivel APerceptibleHíbrido

    Cuando la secuencia en que se presenta el contenido afecta a su significado, se puede determinar por software una secuencia de lectura correcta.

    Cómo verificarlo

    • Desactivar CSS y verificar que el orden del contenido tenga sentido
    • Usar lector de pantalla para verificar el orden de lectura
    • Verificar que el orden del DOM coincida con el orden visual
    • Confirmar que el uso de flexbox/grid no altere el orden lógico

    Correcto

    <!-- Orden lógico en el DOM -->
    <main>
      <h1>Título</h1>
      <p>Introducción</p>
      <section>
        <h2>Sección 1</h2>
        <p>Contenido de sección 1</p>
      </section>
    </main>

    Incorrecto

    <!-- Orden visual con CSS pero DOM desordenado -->
    <main>
      <section style="order: 2">
        <h2>Sección 1</h2>
        <p>Contenido</p>
      </section>
      <h1 style="order: 1">Título</h1>
      <p style="order: 3">Introducción</p>
    </main>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.3.3Características sensorialesNivel APerceptibleManual

    Las instrucciones proporcionadas para entender y operar el contenido no dependen únicamente de características sensoriales.

    Cómo verificarlo

    • Revisar todas las instrucciones en el sitio
    • Verificar que no dependan solo de forma, tamaño, ubicación visual, orientación o sonido
    • Confirmar que las instrucciones incluyan identificadores programáticos
    • Verificar que los usuarios puedan seguir instrucciones sin percepción visual

    Correcto

    <!-- Instrucción con múltiples referencias -->
    <p>Haz clic en el botón "Enviar" (botón azul en la parte inferior) para continuar.</p>
    <button id="submit-btn" class="primary-button">Enviar</button>
    
    <!-- Referencia programática -->
    <p>Completa el <a href="#form-section">formulario de contacto</a> a continuación.</p>

    Incorrecto

    <!-- Solo referencia visual -->
    <p>Haz clic en el botón azul de abajo para continuar.</p>
    <button class="blue-button">Enviar</button>
    
    <!-- Solo referencia de posición -->
    <p>Completa el formulario a la derecha.</p>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.3.4OrientaciónNivel AAPerceptibleAutomatizable

    El contenido no restringe su vista y operación a una sola orientación de pantalla, como vertical u horizontal.

    Cómo verificarlo

    • Rotar el dispositivo o cambiar la orientación del navegador
    • Verificar que el contenido se adapte a ambas orientaciones
    • Confirmar que toda la funcionalidad esté disponible en ambas orientaciones
    • Verificar que no haya bloqueos de orientación innecesarios

    Correcto

    /* CSS responsive que funciona en ambas orientaciones */
    @media (max-width: 768px) {
      .container {
        flex-direction: column;
      }
    }
    
    @media (min-width: 769px) {
      .container {
        flex-direction: row;
      }
    }

    Incorrecto

    /* Bloqueo de orientación innecesario */
    <meta name="screen-orientation" content="portrait">
    
    /* CSS que solo funciona en una orientación */
    @media (orientation: portrait) {
      .content { display: block; }
    }
    @media (orientation: landscape) {
      .content { display: none; }
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.3.5Identificar propósito de entradaNivel AAPerceptibleAutomatizable

    El propósito de cada campo de entrada que recopila información sobre el usuario puede ser determinado por software.

    Cómo verificarlo

    • Inspeccionar todos los campos de formulario
    • Verificar que usen atributos autocomplete apropiados
    • Confirmar que los campos comunes (nombre, email, teléfono) tengan autocomplete
    • Verificar que los navegadores puedan autocompletar los campos

    Correcto

    <form>
      <label for="name">Nombre completo</label>
      <input type="text" id="name" name="name" autocomplete="name">
      
      <label for="email">Correo electrónico</label>
      <input type="email" id="email" name="email" autocomplete="email">
      
      <label for="tel">Teléfono</label>
      <input type="tel" id="tel" name="tel" autocomplete="tel">
      
      <label for="address">Dirección</label>
      <input type="text" id="address" name="address" autocomplete="street-address">
    </form>

    Incorrecto

    <form>
      <label for="name">Nombre completo</label>
      <input type="text" id="name" name="name">
      
      <label for="email">Correo electrónico</label>
      <input type="text" id="email" name="email">
    </form>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.4.1Uso del colorNivel APerceptibleHíbrido

    El color no se usa como único medio visual para transmitir información, indicar una acción o distinguir un elemento.

    Cómo verificarlo

    • Identificar elementos que usen color para transmitir información
    • Verificar que existan indicadores adicionales (iconos, texto, patrones)
    • Usar simulador de daltonismo para verificar la información
    • Confirmar que los enlaces se distingan por más que solo color

    Correcto

    <!-- Error con icono y color -->
    <div class="error">
      <svg class="icon-error">...</svg>
      <span>Error: El campo es requerido</span>
    </div>
    
    <!-- Enlace con subrayado -->
    <a href="/page" style="color: blue; text-decoration: underline;">
      Ir a la página
    </a>
    
    <!-- Gráfico con patrones -->
    <div class="chart">
      <div class="bar bar-pattern-1" style="background: repeating-linear-gradient(45deg, #f00, #f00 10px, #fff 10px, #fff 20px);">
        Ventas
      </div>
    </div>

    Incorrecto

    <!-- Error solo con color -->
    <div style="color: red;">
      El campo es requerido
    </div>
    
    <!-- Enlace solo con color -->
    <a href="/page" style="color: blue; text-decoration: none;">
      Ir a la página
    </a>
    
    <!-- Gráfico solo con colores -->
    <div class="chart">
      <div style="background: red;">Ventas</div>
      <div style="background: blue;">Gastos</div>
    </div>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.4.2Control del audioNivel APerceptibleManual

    Si el audio en una página web se reproduce automáticamente durante más de 3 segundos, se proporciona un mecanismo para pausarlo o detenerlo.

    Cómo verificarlo

    • Cargar la página y verificar si hay audio automático
    • Medir si el audio dura más de 3 segundos
    • Verificar que exista un control visible para pausar/detener
    • Confirmar que el control esté al inicio de la página

    Correcto

    <!-- Audio con controles -->
    <audio controls>
      <source src="audio.mp3" type="audio/mpeg">
    </audio>
    
    <!-- Audio con botón de control -->
    <button id="toggle-audio" aria-label="Pausar audio de fondo">
      Pausar audio
    </button>
    <audio id="bg-audio" loop>
      <source src="background.mp3" type="audio/mpeg">
    </audio>

    Incorrecto

    <!-- Audio automático sin controles -->
    <audio autoplay loop>
      <source src="background.mp3" type="audio/mpeg">
    </audio>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.4.3Contraste (mínimo)Nivel AAPerceptibleAutomatizable

    El texto y las imágenes de texto tienen una relación de contraste de al menos 4.5:1, excepto para texto grande que requiere 3:1.

    Cómo verificarlo

    • Usar herramienta de contraste (ej: WebAIM Contrast Checker)
    • Verificar contraste de todo el texto normal (4.5:1 mínimo)
    • Verificar contraste de texto grande (3:1 mínimo para 18pt+ o 14pt+ bold)
    • Verificar contraste en todos los estados (normal, hover, focus, disabled)

    Correcto

    /* Contraste adecuado */
    .text {
      color: #000000; /* Negro */
      background-color: #FFFFFF; /* Blanco */
      /* Contraste: 21:1 */
    }
    
    .button {
      color: #FFFFFF; /* Blanco */
      background-color: #0066CC; /* Azul */
      /* Contraste: 7.7:1 */
    }

    Incorrecto

    /* Contraste insuficiente */
    .text {
      color: #777777; /* Gris claro */
      background-color: #FFFFFF; /* Blanco */
      /* Contraste: 2.8:1 - FALLA */
    }
    
    .button {
      color: #FFFF00; /* Amarillo */
      background-color: #FFFFFF; /* Blanco */
      /* Contraste: 1.1:1 - FALLA */
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.4.4Cambio de tamaño del textoNivel AAPerceptibleAutomatizable

    El texto puede ser redimensionado sin tecnología de asistencia hasta un 200% sin pérdida de contenido o funcionalidad.

    Cómo verificarlo

    • Aumentar el zoom del navegador al 200%
    • Verificar que todo el texto sea legible
    • Confirmar que no haya pérdida de contenido
    • Verificar que toda la funcionalidad siga disponible
    • Confirmar que no aparezca scroll horizontal

    Correcto

    /* Usar unidades relativas */
    body {
      font-size: 16px; /* Base */
    }
    
    h1 {
      font-size: 2rem; /* 32px, escala con zoom */
    }
    
    .container {
      max-width: 100%;
      padding: 1rem;
    }

    Incorrecto

    /* Usar unidades fijas */
    body {
      font-size: 16px;
    }
    
    h1 {
      font-size: 32px; /* No escala bien */
    }
    
    .container {
      width: 1200px; /* Ancho fijo causa problemas */
      overflow: hidden; /* Oculta contenido */
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.4.5Imágenes de textoNivel AAPerceptibleManual

    Si se pueden usar las tecnologías para conseguir la presentación visual, se usa texto para transmitir información en vez de imágenes de texto.

    Cómo verificarlo

    • Identificar todas las imágenes que contienen texto
    • Verificar si el texto podría implementarse con HTML/CSS
    • Confirmar que las imágenes de texto sean esenciales (logos, marcas)
    • Verificar que las imágenes de texto sean personalizables si es necesario

    Correcto

    <!-- Usar texto real con CSS -->
    <h1 class="fancy-title">Título Elegante</h1>
    
    <style>
    .fancy-title {
      font-family: 'Georgia', serif;
      font-size: 3rem;
      color: #333;
      text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
    }
    </style>
    
    <!-- Logo (excepción permitida) -->
    <img src="logo.png" alt="Empresa XYZ">

    Incorrecto

    <!-- Imagen de texto innecesaria -->
    <img src="titulo-elegante.png" alt="Título Elegante">
    
    <!-- Botón como imagen -->
    <img src="boton-enviar.png" alt="Enviar">
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.4.10ReflujoNivel AAPerceptibleAutomatizable

    El contenido puede presentarse sin pérdida de información o funcionalidad y sin requerir desplazamiento en dos dimensiones para un ancho de 320 píxeles CSS.

    Cómo verificarlo

    • Redimensionar el navegador a 320px de ancho
    • Verificar que no aparezca scroll horizontal
    • Confirmar que todo el contenido sea visible
    • Verificar que toda la funcionalidad esté disponible
    • Probar en dispositivos móviles reales

    Correcto

    /* Diseño responsive */
    .container {
      max-width: 100%;
      padding: 1rem;
    }
    
    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
      gap: 1rem;
    }
    
    @media (max-width: 320px) {
      .grid {
        grid-template-columns: 1fr;
      }
    }

    Incorrecto

    /* Ancho fijo */
    .container {
      width: 1200px;
      min-width: 1200px;
    }
    
    .table {
      width: 1000px;
      overflow-x: scroll; /* Requiere scroll horizontal */
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.4.11Contraste no textualNivel AAPerceptibleAutomatizable

    Los componentes de la interfaz de usuario y los objetos gráficos tienen una relación de contraste de al menos 3:1 contra colores adyacentes.

    Cómo verificarlo

    • Identificar todos los componentes de UI (botones, campos, iconos)
    • Verificar contraste de bordes y estados (3:1 mínimo)
    • Verificar contraste de iconos y gráficos informativos
    • Confirmar contraste en estados hover, focus, active

    Correcto

    /* Botón con buen contraste */
    .button {
      background-color: #0066CC;
      border: 2px solid #004080;
      color: #FFFFFF;
      /* Contraste borde/fondo: 3.2:1 ✓ */
    }
    
    /* Campo de formulario */
    .input {
      border: 2px solid #666666;
      background-color: #FFFFFF;
      /* Contraste: 5.7:1 ✓ */
    }
    
    .input:focus {
      border-color: #0066CC;
      outline: 2px solid #0066CC;
      /* Contraste: 7.7:1 ✓ */
    }

    Incorrecto

    /* Contraste insuficiente */
    .button {
      background-color: #E0E0E0;
      border: 1px solid #D0D0D0;
      /* Contraste: 1.2:1 ✗ */
    }
    
    .input {
      border: 1px solid #CCCCCC;
      background-color: #FFFFFF;
      /* Contraste: 1.6:1 ✗ */
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.4.12Espaciado del textoNivel AAPerceptibleAutomatizable

    No se pierde contenido o funcionalidad cuando se ajusta el espaciado del texto (altura de línea, espaciado de párrafos, letras y palabras).

    Cómo verificarlo

    • Aplicar estilos de espaciado aumentado con bookmarklet o extensión
    • Verificar: line-height 1.5x, paragraph spacing 2x, letter-spacing 0.12x, word-spacing 0.16x
    • Confirmar que no se pierda contenido
    • Verificar que no haya superposición de texto
    • Confirmar que toda la funcionalidad siga disponible

    Correcto

    /* Diseño flexible que soporta espaciado */
    .text-content {
      max-width: 100%;
      overflow-wrap: break-word;
    }
    
    .container {
      min-height: fit-content;
      padding: 1rem;
    }
    
    /* No usar height fijo en contenedores de texto */
    .card {
      min-height: 200px; /* min-height en lugar de height */
    }

    Incorrecto

    /* Altura fija que corta texto */
    .text-content {
      height: 100px;
      overflow: hidden;
    }
    
    /* Contenedor que no se expande */
    .container {
      height: 300px;
      overflow: hidden;
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 1.4.13Contenido al pasar o enfocarNivel AAPerceptibleHíbrido

    El contenido adicional que aparece al pasar el cursor o al enfocar debe ser descartable, hoverable y persistente.

    Cómo verificarlo

    • Identificar tooltips, menús desplegables, y contenido emergente
    • Verificar que se pueda cerrar con Escape sin mover el foco
    • Confirmar que el cursor pueda moverse sobre el contenido emergente
    • Verificar que el contenido permanezca visible hasta que el usuario lo descarte

    Correcto

    <!-- Tooltip accesible -->
    <button 
      aria-describedby="tooltip"
      onmouseenter="showTooltip()"
      onfocus="showTooltip()"
      onmouseleave="hideTooltip()"
      onblur="hideTooltip()"
    >
      Ayuda
    </button>
    <div 
      id="tooltip" 
      role="tooltip"
      onmouseenter="keepTooltipVisible()"
      onmouseleave="hideTooltip()"
    >
      Información de ayuda
    </div>
    
    <script>
    // Permitir cerrar con Escape
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape') hideTooltip()
    })
    </script>

    Incorrecto

    <!-- Tooltip no accesible -->
    <button title="Información de ayuda">
      Ayuda
    </button>
    <!-- El atributo title no es hoverable ni descartable -->
    
    <!-- Menú que desaparece inmediatamente -->
    <div onmouseleave="hideMenu()" style="display:none">
      <a href="/page1">Opción 1</a>
    </div>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.1.1TecladoNivel AOperableAutomatizable

    Toda la funcionalidad del contenido es operable a través de una interfaz de teclado.

    Cómo verificarlo

    • Desconectar el mouse y usar solo el teclado
    • Verificar que se pueda navegar con Tab/Shift+Tab
    • Confirmar que se pueda activar con Enter/Espacio
    • Verificar que toda la funcionalidad sea accesible
    • Probar formularios, menús, modales, carruseles

    Correcto

    <!-- Botón nativo (accesible por teclado) -->
    <button onclick="doAction()">Hacer algo</button>
    
    <!-- Enlace nativo -->
    <a href="/page">Ir a página</a>
    
    <!-- Elemento interactivo personalizado -->
    <div 
      role="button"
      tabindex="0"
      onclick="doAction()"
      onkeydown="if(event.key==='Enter'||event.key===' ') doAction()"
    >
      Acción personalizada
    </div>

    Incorrecto

    <!-- Div sin accesibilidad de teclado -->
    <div onclick="doAction()">Hacer algo</div>
    
    <!-- Enlace sin href -->
    <a onclick="doAction()">Ir a página</a>
    
    <!-- Elemento que requiere mouse -->
    <div onmouseover="showMenu()">Menú</div>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.1.2Sin trampas de tecladoNivel AOperableAutomatizable

    Si el foco del teclado puede moverse a un componente, entonces puede moverse fuera de ese componente usando solo el teclado.

    Cómo verificarlo

    • Navegar por toda la página con teclado
    • Verificar que el foco nunca quede atrapado
    • Probar modales y diálogos (deben cerrarse con Escape)
    • Verificar que se pueda salir de todos los componentes
    • Confirmar que las instrucciones de salida estén disponibles si es necesario

    Correcto

    <!-- Modal accesible -->
    <dialog id="modal" aria-labelledby="modal-title">
      <h2 id="modal-title">Título del modal</h2>
      <p>Contenido...</p>
      <button onclick="closeModal()">Cerrar</button>
    </dialog>
    
    <script>
    // Cerrar con Escape
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape' && modal.open) {
        closeModal()
      }
    })
    
    // Trap focus dentro del modal
    function trapFocus(element) {
      const focusableElements = element.querySelectorAll(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      )
      const firstElement = focusableElements[0]
      const lastElement = focusableElements[focusableElements.length - 1]
      
      element.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()
          }
        }
      })
    }
    </script>

    Incorrecto

    <!-- Modal sin escape -->
    <div id="modal" style="display:none">
      <h2>Título</h2>
      <p>Contenido...</p>
      <!-- Sin botón de cerrar ni manejo de Escape -->
    </div>
    
    <!-- Iframe sin forma de salir -->
    <iframe src="external.html"></iframe>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.1.4Atajos de teclado de caracteresNivel AOperableManual

    Si se implementa un atajo de teclado usando solo caracteres, entonces se puede desactivar, reasignar o solo está activo cuando el componente tiene el foco.

    Cómo verificarlo

    • Identificar todos los atajos de teclado de un solo carácter
    • Verificar que se puedan desactivar en configuración
    • Confirmar que se puedan reasignar a combinaciones con modificadores
    • Verificar que solo funcionen cuando el componente relevante tiene foco

    Correcto

    <!-- Atajo con modificador -->
    <button 
      accesskey="s"
      title="Guardar (Ctrl+S)"
    >
      Guardar
    </button>
    
    <!-- Atajo solo activo en contexto -->
    <div 
      role="application"
      onkeydown="handleShortcut(event)"
      tabindex="0"
    >
      <p>Presiona 's' para guardar (solo cuando este panel tiene foco)</p>
    </div>
    
    <script>
    function handleShortcut(e) {
      // Solo funciona si el elemento tiene foco
      if (e.key === 's' && !e.ctrlKey && !e.altKey) {
        e.preventDefault()
        save()
      }
    }
    </script>

    Incorrecto

    <!-- Atajo global de un solo carácter -->
    <script>
    document.addEventListener('keydown', (e) => {
      if (e.key === 's') {
        // Interfiere con escritura en campos de texto
        save()
      }
    })
    </script>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.2.1Tiempo ajustableNivel AOperableHíbrido

    Para cada límite de tiempo establecido por el contenido, se cumple al menos una de las siguientes condiciones: desactivar, ajustar o extender.

    Cómo verificarlo

    • Identificar funcionalidades con límites de tiempo
    • Verificar que se pueda desactivar el límite antes de encontrarlo
    • Confirmar que se pueda ajustar el tiempo (al menos 10x el predeterminado)
    • Verificar que se pueda extender con advertencia (al menos 20 segundos antes)
    • Probar sesiones, formularios con tiempo, presentaciones automáticas

    Correcto

    <!-- Advertencia de tiempo con opción de extender -->
    <div id="timeout-warning" role="alert" style="display:none">
      <p>Tu sesión expirará en <span id="countdown">60</span> segundos.</p>
      <button onclick="extendSession()">Extender sesión</button>
    </div>
    
    <script>
    let timeoutId
    let warningShown = false
    
    function startSession() {
      // Advertir 60 segundos antes
      setTimeout(() => {
        showTimeoutWarning()
      }, (sessionDuration - 60) * 1000)
      
      // Timeout real
      timeoutId = setTimeout(() => {
        logout()
      }, sessionDuration * 1000)
    }
    
    function extendSession() {
      clearTimeout(timeoutId)
      hideTimeoutWarning()
      startSession()
    }
    </script>

    Incorrecto

    <!-- Timeout sin advertencia ni opción de extender -->
    <script>
    setTimeout(() => {
      logout() // Usuario pierde su trabajo sin advertencia
    }, 300000) // 5 minutos
    </script>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.2.2Pausar, detener, ocultarNivel AOperableManual

    Para información en movimiento, parpadeante, desplazándose o actualizándose automáticamente, se proporciona un mecanismo para pausar, detener u ocultar.

    Cómo verificarlo

    • Identificar contenido en movimiento, carruseles, animaciones
    • Verificar que dure más de 5 segundos
    • Confirmar que exista control para pausar/detener
    • Verificar que el control sea accesible por teclado
    • Probar actualizaciones automáticas (noticias, feeds)

    Correcto

    <!-- Carrusel con controles -->
    <div class="carousel">
      <div class="slides">...</div>
      <button onclick="pauseCarousel()" aria-label="Pausar carrusel">
        Pausar
      </button>
      <button onclick="playCarousel()" aria-label="Reproducir carrusel">
        Reproducir
      </button>
    </div>
    
    <!-- Actualización automática con control -->
    <div class="live-feed">
      <button onclick="toggleAutoUpdate()" aria-pressed="true">
        Actualización automática: Activada
      </button>
      <div id="feed-content">...</div>
    </div>

    Incorrecto

    <!-- Carrusel sin controles -->
    <div class="carousel">
      <div class="slides">...</div>
    </div>
    <script>
    setInterval(() => {
      nextSlide() // Sin forma de pausar
    }, 3000)
    </script>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.3.1Umbral de tres destellos o menosNivel AOperableManual

    Las páginas web no contienen nada que destelle más de tres veces en un segundo, o el destello está por debajo de los umbrales de destello general y destello rojo.

    Cómo verificarlo

    • Identificar contenido con destellos, animaciones, videos
    • Verificar que no destelle más de 3 veces por segundo
    • Confirmar que el área de destello sea pequeña
    • Verificar que no haya destellos rojos intensos
    • Usar herramientas de análisis de destellos si está disponible

    Correcto

    /* Animación suave sin destellos */
    @keyframes fadeIn {
      from { opacity: 0; }
      to { opacity: 1; }
    }
    
    .element {
      animation: fadeIn 1s ease-in;
    }
    
    /* Transición suave */
    .button {
      transition: background-color 0.3s ease;
    }

    Incorrecto

    /* Animación con destellos rápidos */
    @keyframes flash {
      0%, 100% { opacity: 1; }
      50% { opacity: 0; }
    }
    
    .element {
      animation: flash 0.1s infinite; /* Destella 10 veces por segundo */
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.4.1Evitar bloquesNivel AOperableAutomatizable

    Se proporciona un mecanismo para evitar bloques de contenido que se repiten en múltiples páginas web.

    Cómo verificarlo

    • Verificar que exista un enlace 'Saltar al contenido principal' al inicio
    • Confirmar que el enlace sea el primer elemento enfocable
    • Verificar que el enlace funcione correctamente
    • Confirmar que lleve al contenido principal, no a la navegación
    • Probar con teclado (Tab debe enfocar el enlace primero)

    Correcto

    <!-- Enlace para saltar al contenido -->
    <body>
      <a href="#main-content" class="skip-link">
        Saltar al contenido principal
      </a>
      
      <header>
        <nav>...</nav>
      </header>
      
      <main id="main-content" tabindex="-1">
        <h1>Contenido principal</h1>
        ...
      </main>
    </body>
    
    <style>
    .skip-link {
      position: absolute;
      top: -40px;
      left: 0;
      background: #000;
      color: #fff;
      padding: 8px;
      z-index: 100;
    }
    
    .skip-link:focus {
      top: 0;
    }
    </style>

    Incorrecto

    <!-- Sin mecanismo para saltar bloques -->
    <body>
      <header>
        <nav>
          <!-- 20+ enlaces de navegación -->
        </nav>
      </header>
      
      <main>
        <h1>Contenido principal</h1>
        ...
      </main>
    </body>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.4.2Página tituladaNivel AOperableAutomatizable

    Las páginas web tienen títulos que describen su tema o propósito.

    Cómo verificarlo

    • Verificar que cada página tenga un elemento <title>
    • Confirmar que el título sea descriptivo y único
    • Verificar que el título identifique el contenido de la página
    • Confirmar que el título incluya el nombre del sitio (opcional pero recomendado)
    • Verificar que el título cambie en aplicaciones de una sola página (SPA)

    Correcto

    <!-- Título descriptivo y único -->
    <head>
      <title>Formulario de Contacto - Empresa XYZ</title>
    </head>
    
    <!-- En SPA, actualizar el título -->
    <script>
    function navigateTo(page) {
      // Actualizar contenido
      loadPage(page)
      
      // Actualizar título
      document.title = `${page.title} - Empresa XYZ`
    }
    </script>

    Incorrecto

    <!-- Título genérico -->
    <head>
      <title>Página</title>
    </head>
    
    <!-- Título sin contexto -->
    <head>
      <title>Inicio</title>
    </head>
    
    <!-- Sin título -->
    <head>
    </head>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.4.3Orden del focoNivel AOperableAutomatizable

    Si una página web puede ser navegada secuencialmente y las secuencias de navegación afectan al significado o funcionamiento, los componentes enfocables reciben el foco en un orden que preserva el significado y la operabilidad.

    Cómo verificarlo

    • Navegar por la página usando solo Tab
    • Verificar que el orden del foco sea lógico
    • Confirmar que el orden del foco siga el orden visual
    • Verificar que no haya saltos confusos en el foco
    • Probar formularios, menús, modales

    Correcto

    <!-- Orden lógico del DOM -->
    <form>
      <label for="name">Nombre</label>
      <input type="text" id="name">
      
      <label for="email">Email</label>
      <input type="email" id="email">
      
      <button type="submit">Enviar</button>
    </form>
    
    <!-- Usar tabindex solo cuando sea necesario -->
    <div role="dialog">
      <h2 tabindex="-1">Título del diálogo</h2>
      <button>Aceptar</button>
      <button>Cancelar</button>
    </div>

    Incorrecto

    <!-- Orden del DOM no coincide con orden visual -->
    <div style="display: flex; flex-direction: column-reverse;">
      <button>Botón 1</button> <!-- Visualmente último, pero primero en DOM -->
      <button>Botón 2</button>
      <button>Botón 3</button> <!-- Visualmente primero, pero último en DOM -->
    </div>
    
    <!-- Uso incorrecto de tabindex -->
    <button tabindex="3">Primero visualmente</button>
    <button tabindex="1">Segundo visualmente</button>
    <button tabindex="2">Tercero visualmente</button>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.4.4Propósito de los enlaces (en contexto)Nivel AOperableAutomatizable

    El propósito de cada enlace puede ser determinado por el texto del enlace solo o por el texto del enlace junto con su contexto de enlace determinado por software.

    Cómo verificarlo

    • Revisar todos los enlaces en la página
    • Verificar que el texto del enlace sea descriptivo
    • Confirmar que enlaces con el mismo texto vayan al mismo destino
    • Verificar que no haya enlaces genéricos como 'clic aquí' o 'más información'
    • Usar lector de pantalla para listar todos los enlaces

    Correcto

    <!-- Enlaces descriptivos -->
    <a href="/productos/laptop-x1">Ver detalles de Laptop X1</a>
    
    <a href="/contacto">Contactar con soporte técnico</a>
    
    <!-- Enlace con contexto -->
    <article>
      <h2>Laptop X1</h2>
      <p>Descripción del producto...</p>
      <a href="/productos/laptop-x1">Leer más sobre Laptop X1</a>
    </article>
    
    <!-- Enlace con aria-label cuando sea necesario -->
    <a href="/productos/laptop-x1" aria-label="Ver detalles de Laptop X1">
      Ver detalles
    </a>

    Incorrecto

    <!-- Enlaces genéricos -->
    <a href="/productos/laptop-x1">Clic aquí</a>
    
    <a href="/contacto">Más información</a>
    
    <!-- Enlaces ambiguos -->
    <a href="/producto1">Leer más</a>
    <a href="/producto2">Leer más</a>
    <a href="/producto3">Leer más</a>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.4.5Múltiples víasNivel AAOperableManual

    Se proporciona más de una vía para localizar una página web dentro de un conjunto de páginas web.

    Cómo verificarlo

    • Verificar que existan al menos dos formas de encontrar páginas
    • Confirmar presencia de: menú de navegación, búsqueda, mapa del sitio, índice, breadcrumbs
    • Verificar que las vías sean funcionales
    • Confirmar que las vías estén disponibles en todas las páginas

    Correcto

    <!-- Navegación principal -->
    <nav aria-label="Navegación principal">
      <ul>
        <li><a href="/">Inicio</a></li>
        <li><a href="/productos">Productos</a></li>
        <li><a href="/contacto">Contacto</a></li>
      </ul>
    </nav>
    
    <!-- Búsqueda -->
    <form role="search">
      <label for="search">Buscar en el sitio</label>
      <input type="search" id="search" name="q">
      <button type="submit">Buscar</button>
    </form>
    
    <!-- Breadcrumbs -->
    <nav aria-label="Breadcrumb">
      <ol>
        <li><a href="/">Inicio</a></li>
        <li><a href="/productos">Productos</a></li>
        <li aria-current="page">Laptop X1</li>
      </ol>
    </nav>
    
    <!-- Mapa del sitio -->
    <a href="/sitemap">Mapa del sitio</a>

    Incorrecto

    <!-- Solo una forma de navegar -->
    <nav>
      <ul>
        <li><a href="/">Inicio</a></li>
      </ul>
    </nav>
    <!-- Sin búsqueda, sin mapa del sitio, sin breadcrumbs -->
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.4.6Encabezados y etiquetasNivel AAOperableAutomatizable

    Los encabezados y etiquetas describen el tema o propósito.

    Cómo verificarlo

    • Revisar todos los encabezados (<h1>-<h6>)
    • Verificar que sean descriptivos y claros
    • Confirmar que las etiquetas de formulario describan el propósito del campo
    • Verificar que los encabezados no sean genéricos
    • Usar lector de pantalla para navegar por encabezados

    Correcto

    <!-- Encabezados descriptivos -->
    <h1>Formulario de Registro de Usuario</h1>
    <h2>Información Personal</h2>
    <h3>Dirección de Envío</h3>
    
    <!-- Etiquetas descriptivas -->
    <form>
      <label for="email">Correo electrónico (será usado para login)</label>
      <input type="email" id="email" name="email">
      
      <label for="password">Contraseña (mínimo 8 caracteres)</label>
      <input type="password" id="password" name="password">
    </form>

    Incorrecto

    <!-- Encabezados genéricos -->
    <h1>Formulario</h1>
    <h2>Sección 1</h2>
    <h3>Parte A</h3>
    
    <!-- Etiquetas vagas -->
    <form>
      <label for="field1">Campo 1</label>
      <input type="text" id="field1">
      
      <label for="field2">Entrada</label>
      <input type="text" id="field2">
    </form>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.4.7Foco visibleNivel AAOperableAutomatizable

    Cualquier interfaz de usuario operable por teclado tiene un modo de operación donde el indicador de foco del teclado es visible.

    Cómo verificarlo

    • Navegar por toda la página con Tab
    • Verificar que el foco sea siempre visible
    • Confirmar que el indicador de foco tenga suficiente contraste
    • Verificar que el foco no se oculte detrás de otros elementos
    • Probar en diferentes navegadores y sistemas operativos

    Correcto

    /* Indicador de foco visible y claro */
    a:focus,
    button:focus,
    input:focus {
      outline: 2px solid #0066CC;
      outline-offset: 2px;
    }
    
    /* Estilo personalizado de foco */
    .button:focus {
      outline: none; /* Solo si se proporciona alternativa */
      box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.5);
      border-color: #0066CC;
    }
    
    /* Foco visible en elementos personalizados */
    [role="button"]:focus {
      outline: 2px solid #0066CC;
      outline-offset: 2px;
    }

    Incorrecto

    /* Eliminar outline sin alternativa */
    *:focus {
      outline: none; /* NUNCA hacer esto sin alternativa */
    }
    
    /* Foco con contraste insuficiente */
    a:focus {
      outline: 1px solid #CCCCCC; /* Contraste muy bajo */
    }
    
    /* Foco oculto */
    button:focus {
      outline: none;
      /* Sin alternativa visible */
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.4.11Foco no oscurecido (mínimo)Nivel AAOperableHíbridoNuevo en 2.2

    Cuando un componente de la interfaz de usuario recibe el foco del teclado, el componente no está completamente oculto debido al contenido creado por el autor.

    Cómo verificarlo

    • Navegar por la página con Tab
    • Verificar que los elementos enfocados sean al menos parcialmente visibles
    • Confirmar que headers/footers fijos no oculten el foco
    • Verificar que modales y overlays no oculten elementos enfocados
    • Probar con diferentes tamaños de ventana

    Correcto

    /* Header fijo con espacio para foco */
    header {
      position: fixed;
      top: 0;
      z-index: 100;
    }
    
    main {
      margin-top: 80px; /* Espacio para header */
      scroll-padding-top: 80px; /* Espacio al hacer scroll */
    }
    
    /* Scroll automático al enfocar */
    <script>
    document.addEventListener('focusin', (e) => {
      const element = e.target
      const rect = element.getBoundingClientRect()
      const headerHeight = 80
      
      if (rect.top < headerHeight) {
        element.scrollIntoView({ block: 'center', behavior: 'smooth' })
      }
    })
    </script>

    Incorrecto

    /* Header fijo que oculta elementos */
    header {
      position: fixed;
      top: 0;
      z-index: 100;
      height: 80px;
    }
    
    main {
      /* Sin margen superior, el header oculta contenido */
    }
    
    /* Modal que oculta elementos enfocados */
    .modal-overlay {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      z-index: 9999;
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.5.1Gestos del punteroNivel AOperableManual

    Toda la funcionalidad que usa gestos multipunto o basados en trayectoria puede ser operada con un solo puntero sin un gesto basado en trayectoria.

    Cómo verificarlo

    • Identificar funcionalidades que usen gestos (arrastrar, pellizcar, deslizar)
    • Verificar que existan alternativas con un solo clic/tap
    • Confirmar que mapas, carruseles, zoom tengan controles alternativos
    • Probar con mouse, touch, y tecnologías de asistencia

    Correcto

    <!-- Carrusel con botones alternativos -->
    <div class="carousel">
      <div class="slides" 
           ontouchstart="handleSwipe(event)"
           ontouchmove="handleSwipe(event)">
        ...
      </div>
      <!-- Alternativas con un solo puntero -->
      <button onclick="previousSlide()">Anterior</button>
      <button onclick="nextSlide()">Siguiente</button>
    </div>
    
    <!-- Mapa con controles de zoom -->
    <div class="map">
      <div id="map-container"></div>
      <div class="map-controls">
        <button onclick="zoomIn()">+</button>
        <button onclick="zoomOut()">-</button>
      </div>
    </div>

    Incorrecto

    <!-- Solo gestos multipunto -->
    <div class="map" 
         onpinch="zoom(event)">
      <!-- Sin controles alternativos -->
    </div>
    
    <!-- Solo arrastrar -->
    <div class="slider" 
         ondrag="moveSlider(event)">
      <!-- Sin botones alternativos -->
    </div>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.5.2Cancelación del punteroNivel AOperableManual

    Para funcionalidad que puede ser operada usando un solo puntero, se cumple al menos una de las siguientes: sin evento down, abortar o deshacer, reversión up, esencial.

    Cómo verificarlo

    • Probar todos los elementos interactivos
    • Verificar que la acción ocurra en mouseup/touchend, no en mousedown/touchstart
    • Confirmar que se pueda cancelar moviendo el puntero fuera del elemento
    • Verificar que acciones críticas tengan confirmación

    Correcto

    <!-- Acción en mouseup (correcto) -->
    <button 
      onmouseup="handleAction()"
      ontouchend="handleAction()">
      Eliminar
    </button>
    
    <!-- Acción con confirmación -->
    <button onclick="confirmDelete()">
      Eliminar cuenta
    </button>
    
    <script>
    function confirmDelete() {
      if (confirm('¿Estás seguro de que quieres eliminar tu cuenta?')) {
        deleteAccount()
      }
    }
    </script>

    Incorrecto

    <!-- Acción en mousedown (incorrecto) -->
    <button 
      onmousedown="deleteAccount()"
      ontouchstart="deleteAccount()">
      Eliminar cuenta
    </button>
    
    <!-- Acción destructiva sin confirmación -->
    <button onclick="deleteAccount()">
      Eliminar cuenta
    </button>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.5.3Etiqueta en el nombreNivel AOperableAutomatizable

    Para componentes de interfaz de usuario con etiquetas que incluyen texto o imágenes de texto, el nombre contiene el texto que se presenta visualmente.

    Cómo verificarlo

    • Inspeccionar todos los controles con etiquetas visibles
    • Verificar que el nombre accesible incluya el texto visible
    • Confirmar que el texto visible esté al inicio del nombre accesible
    • Usar lector de pantalla para verificar los nombres anunciados

    Correcto

    <!-- Etiqueta visible coincide con nombre accesible -->
    <button aria-label="Buscar productos en el catálogo">
      Buscar
    </button>
    
    <!-- Mejor: usar solo el texto visible -->
    <button>Buscar</button>
    
    <!-- Input con label visible -->
    <label for="search">Buscar productos</label>
    <input type="search" id="search" name="search">

    Incorrecto

    <!-- Nombre accesible no incluye texto visible -->
    <button aria-label="Realizar búsqueda">
      Buscar
    </button>
    
    <!-- Texto visible no está en el nombre accesible -->
    <button aria-label="Icono de búsqueda">
      <svg>...</svg>
      Buscar
    </button>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.5.4Activación por movimientoNivel AOperableManual

    La funcionalidad que puede ser operada por movimiento del dispositivo o del usuario también puede ser operada por componentes de interfaz de usuario.

    Cómo verificarlo

    • Identificar funcionalidades activadas por movimiento (sacudir, inclinar)
    • Verificar que existan controles alternativos en la UI
    • Confirmar que se pueda desactivar la detección de movimiento
    • Probar sin mover el dispositivo

    Correcto

    <!-- Funcionalidad con alternativa UI -->
    <div class="shake-to-undo">
      <p>Sacude el dispositivo para deshacer</p>
      <button onclick="undo()">O haz clic aquí para deshacer</button>
    </div>
    
    <!-- Opción para desactivar -->
    <label>
      <input type="checkbox" id="disable-motion" onchange="toggleMotion()">
      Desactivar controles por movimiento
    </label>
    
    <script>
    let motionEnabled = true
    
    function toggleMotion() {
      motionEnabled = !motionEnabled
    }
    
    window.addEventListener('devicemotion', (e) => {
      if (!motionEnabled) return
      // Manejar movimiento
    })
    </script>

    Incorrecto

    <!-- Solo funcionalidad por movimiento -->
    <script>
    window.addEventListener('devicemotion', (e) => {
      if (detectShake(e)) {
        undo() // Sin alternativa UI
      }
    })
    </script>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.5.7Movimientos de arrastreNivel AAOperableHíbridoNuevo en 2.2

    Toda funcionalidad que usa un movimiento de arrastre para su operación puede ser lograda por un solo puntero sin arrastrar.

    Cómo verificarlo

    • Identificar funcionalidades de arrastrar y soltar
    • Verificar que existan alternativas con un solo clic
    • Confirmar que sliders tengan campos de entrada alternativos
    • Probar reordenamiento de listas con botones

    Correcto

    <!-- Slider con campo de entrada alternativo -->
    <label for="volume">Volumen</label>
    <input type="range" id="volume" min="0" max="100" value="50">
    <input type="number" id="volume-input" min="0" max="100" value="50">
    
    <!-- Lista reordenable con botones -->
    <ul>
      <li>
        <span>Elemento 1</span>
        <button onclick="moveUp(0)">↑</button>
        <button onclick="moveDown(0)">↓</button>
      </li>
      <li>
        <span>Elemento 2</span>
        <button onclick="moveUp(1)">↑</button>
        <button onclick="moveDown(1)">↓</button>
      </li>
    </ul>

    Incorrecto

    <!-- Solo arrastrar y soltar -->
    <div draggable="true" ondragstart="drag(event)">
      Arrastra este elemento
    </div>
    <div ondrop="drop(event)" ondragover="allowDrop(event)">
      Suelta aquí
    </div>
    <!-- Sin alternativa con botones -->
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 2.5.8Tamaño del objetivo (mínimo)Nivel AAOperableAutomatizableNuevo en 2.2

    El tamaño del objetivo para entradas de puntero es de al menos 24 por 24 píxeles CSS, excepto cuando se cumple una de las excepciones.

    Cómo verificarlo

    • Medir todos los objetivos interactivos (botones, enlaces, controles)
    • Verificar que tengan al menos 24x24 píxeles CSS
    • Confirmar espaciado adecuado entre objetivos pequeños
    • Usar herramientas de inspección del navegador

    Correcto

    /* Botones con tamaño mínimo */
    .button {
      min-width: 44px; /* Recomendado: 44x44px */
      min-height: 44px;
      padding: 12px 16px;
    }
    
    /* Enlaces con área de clic ampliada */
    a {
      display: inline-block;
      padding: 8px 12px;
      min-height: 24px;
    }
    
    /* Iconos con padding para aumentar área de clic */
    .icon-button {
      width: 24px;
      height: 24px;
      padding: 10px; /* Área total: 44x44px */
    }

    Incorrecto

    /* Objetivos muy pequeños */
    .icon-button {
      width: 16px;
      height: 16px;
      padding: 0;
    }
    
    /* Enlaces sin área de clic suficiente */
    a {
      font-size: 12px;
      line-height: 1;
      /* Área de clic muy pequeña */
    }
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.1.1Idioma de la páginaNivel AComprensibleAutomatizable

    El idioma predeterminado de cada página web puede ser determinado por software.

    Cómo verificarlo

    • Inspeccionar el elemento <html>
    • Verificar que tenga atributo lang
    • Confirmar que el código de idioma sea válido (ISO 639-1)
    • Verificar que el idioma coincida con el contenido principal

    Correcto

    <!DOCTYPE html>
    <html lang="es">
    <head>
      <meta charset="UTF-8">
      <title>Mi Sitio Web</title>
    </head>
    <body>
      <h1>Bienvenido</h1>
    </body>
    </html>
    
    <!-- Para español de México -->
    <html lang="es-MX">
    
    <!-- Para inglés de Estados Unidos -->
    <html lang="en-US">

    Incorrecto

    <!DOCTYPE html>
    <html>
    <head>
      <title>Mi Sitio Web</title>
    </head>
    <body>
      <h1>Bienvenido</h1>
    </body>
    </html>
    
    <!-- Código de idioma inválido -->
    <html lang="spanish">
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.1.2Idioma de las partesNivel AAComprensibleAutomatizable

    El idioma de cada pasaje o frase en el contenido puede ser determinado por software excepto para nombres propios, términos técnicos, etc.

    Cómo verificarlo

    • Identificar contenido en idiomas diferentes al principal
    • Verificar que tengan atributo lang apropiado
    • Confirmar que citas en otros idiomas estén marcadas
    • Verificar que cambios de idioma sean detectables por lectores de pantalla

    Correcto

    <!-- Contenido principal en español -->
    <html lang="es">
    <body>
      <p>Este es un párrafo en español.</p>
      
      <!-- Frase en inglés -->
      <p>Como dice el refrán: <span lang="en">"Time is money"</span></p>
      
      <!-- Cita en francés -->
      <blockquote lang="fr">
        <p>La vie est belle</p>
      </blockquote>
      
      <!-- Lista con elementos en diferentes idiomas -->
      <ul>
        <li>Español</li>
        <li lang="en">English</li>
        <li lang="fr">Français</li>
      </ul>
    </body>
    </html>

    Incorrecto

    <!-- Sin marcado de idioma -->
    <html lang="es">
    <body>
      <p>Este es un párrafo en español.</p>
      <p>Como dice el refrán: "Time is money"</p>
      <blockquote>
        <p>La vie est belle</p>
      </blockquote>
    </body>
    </html>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.2.1Al recibir el focoNivel AComprensibleAutomatizable

    Cuando cualquier componente recibe el foco, no inicia un cambio de contexto.

    Cómo verificarlo

    • Navegar por la página con Tab
    • Verificar que enfocar elementos no cause cambios inesperados
    • Confirmar que no se abran ventanas automáticamente
    • Verificar que no se envíen formularios al enfocar
    • Confirmar que no cambie la página actual

    Correcto

    <!-- Acción requiere activación explícita -->
    <select id="language" onchange="changeLanguage()">
      <option value="es">Español</option>
      <option value="en">English</option>
    </select>
    <button onclick="applyLanguage()">Aplicar</button>
    
    <!-- Advertencia antes de cambio de contexto -->
    <a href="/external-site" 
       onclick="return confirm('Estás a punto de salir del sitio. ¿Continuar?')">
      Sitio externo
    </a>

    Incorrecto

    <!-- Cambio automático al enfocar -->
    <select id="language" onfocus="changeLanguage()">
      <option value="es">Español</option>
      <option value="en">English</option>
    </select>
    
    <!-- Envío automático al enfocar -->
    <input type="text" onfocus="submitForm()">
    
    <!-- Ventana emergente al enfocar -->
    <button onfocus="window.open('/popup')">
      Información
    </button>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.2.2Al ingresar datosNivel AComprensibleAutomatizable

    Cambiar la configuración de cualquier componente de interfaz de usuario no provoca automáticamente un cambio de contexto.

    Cómo verificarlo

    • Interactuar con todos los controles de formulario
    • Verificar que cambios no causen navegación automática
    • Confirmar que se requiera activación explícita (botón Enviar)
    • Verificar que cambios en select no cambien la página
    • Probar checkboxes y radio buttons

    Correcto

    <!-- Formulario con botón de envío -->
    <form>
      <label for="country">País</label>
      <select id="country" name="country">
        <option value="mx">México</option>
        <option value="us">Estados Unidos</option>
      </select>
      
      <button type="submit">Continuar</button>
    </form>
    
    <!-- Cambio con advertencia -->
    <select id="language" onchange="warnLanguageChange()">
      <option value="es">Español</option>
      <option value="en">English</option>
    </select>
    
    <script>
    function warnLanguageChange() {
      const confirmed = confirm('¿Cambiar idioma? La página se recargará.')
      if (confirmed) {
        changeLanguage()
      }
    }
    </script>

    Incorrecto

    <!-- Cambio automático al seleccionar -->
    <select id="country" onchange="window.location='/country/' + this.value">
      <option value="mx">México</option>
      <option value="us">Estados Unidos</option>
    </select>
    
    <!-- Envío automático al cambiar -->
    <form>
      <input type="checkbox" onchange="this.form.submit()">
    </form>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.2.3Navegación consistenteNivel AAComprensibleAutomatizable

    Los mecanismos de navegación que se repiten en múltiples páginas web dentro de un conjunto de páginas web ocurren en el mismo orden relativo cada vez que se repiten.

    Cómo verificarlo

    • Navegar por múltiples páginas del sitio
    • Verificar que el menú de navegación esté en la misma posición
    • Confirmar que los elementos del menú estén en el mismo orden
    • Verificar que elementos repetidos (header, footer) sean consistentes
    • Confirmar que la estructura sea predecible

    Correcto

    <!-- Navegación consistente en todas las páginas -->
    <!-- Página 1 -->
    <nav>
      <ul>
        <li><a href="/">Inicio</a></li>
        <li><a href="/productos">Productos</a></li>
        <li><a href="/servicios">Servicios</a></li>
        <li><a href="/contacto">Contacto</a></li>
      </ul>
    </nav>
    
    <!-- Página 2 - mismo orden -->
    <nav>
      <ul>
        <li><a href="/">Inicio</a></li>
        <li><a href="/productos">Productos</a></li>
        <li><a href="/servicios">Servicios</a></li>
        <li><a href="/contacto">Contacto</a></li>
      </ul>
    </nav>

    Incorrecto

    <!-- Orden inconsistente -->
    <!-- Página 1 -->
    <nav>
      <ul>
        <li><a href="/">Inicio</a></li>
        <li><a href="/productos">Productos</a></li>
        <li><a href="/contacto">Contacto</a></li>
      </ul>
    </nav>
    
    <!-- Página 2 - orden diferente -->
    <nav>
      <ul>
        <li><a href="/contacto">Contacto</a></li>
        <li><a href="/">Inicio</a></li>
        <li><a href="/productos">Productos</a></li>
      </ul>
    </nav>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.2.4Identificación consistenteNivel AAComprensibleAutomatizable

    Los componentes que tienen la misma funcionalidad dentro de un conjunto de páginas web se identifican de forma coherente.

    Cómo verificarlo

    • Identificar componentes con la misma función en diferentes páginas
    • Verificar que usen el mismo texto/etiqueta
    • Confirmar que usen los mismos iconos
    • Verificar que el comportamiento sea consistente
    • Probar botones de búsqueda, enlaces de ayuda, etc.

    Correcto

    <!-- Botón de búsqueda consistente -->
    <!-- Página 1 -->
    <button aria-label="Buscar">
      <svg>...</svg>
      Buscar
    </button>
    
    <!-- Página 2 - misma etiqueta e icono -->
    <button aria-label="Buscar">
      <svg>...</svg>
      Buscar
    </button>
    
    <!-- Enlace de ayuda consistente -->
    <!-- En todas las páginas -->
    <a href="/ayuda">
      <svg>...</svg>
      Ayuda
    </a>

    Incorrecto

    <!-- Identificación inconsistente -->
    <!-- Página 1 -->
    <button aria-label="Buscar">
      <svg>...</svg>
      Buscar
    </button>
    
    <!-- Página 2 - diferente etiqueta -->
    <button aria-label="Encontrar">
      <svg>...</svg>
      Encontrar
    </button>
    
    <!-- Página 3 - solo icono -->
    <button aria-label="Lupa">
      <svg>...</svg>
    </button>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.2.6Ayuda consistenteNivel AComprensibleManualNuevo en 2.2

    Si una página web contiene cualquiera de los siguientes mecanismos de ayuda, y esos mecanismos se repiten en múltiples páginas web, ocurren en el mismo orden relativo.

    Cómo verificarlo

    • Identificar mecanismos de ayuda (contacto, FAQ, chat, teléfono)
    • Verificar que aparezcan en el mismo orden en todas las páginas
    • Confirmar que estén en la misma ubicación relativa
    • Verificar que sean fácilmente localizables

    Correcto

    <!-- Ayuda consistente en todas las páginas -->
    <footer>
      <nav aria-label="Ayuda">
        <ul>
          <li><a href="/faq">Preguntas Frecuentes</a></li>
          <li><a href="/contacto">Contacto</a></li>
          <li><a href="/chat">Chat en vivo</a></li>
          <li><a href="tel:+1234567890">Teléfono: 123-456-7890</a></li>
        </ul>
      </nav>
    </footer>
    
    <!-- Mismo orden en todas las páginas -->

    Incorrecto

    <!-- Orden inconsistente -->
    <!-- Página 1 -->
    <footer>
      <a href="/faq">FAQ</a>
      <a href="/contacto">Contacto</a>
      <a href="/chat">Chat</a>
    </footer>
    
    <!-- Página 2 - orden diferente -->
    <footer>
      <a href="/chat">Chat</a>
      <a href="/faq">FAQ</a>
      <a href="/contacto">Contacto</a>
    </footer>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.3.1Identificación de erroresNivel AComprensibleAutomatizable

    Si se detecta automáticamente un error en la entrada de datos, el elemento erróneo es identificado y el error se describe al usuario mediante texto.

    Cómo verificarlo

    • Enviar formularios con errores intencionales
    • Verificar que los errores se identifiquen claramente
    • Confirmar que los mensajes de error sean descriptivos
    • Verificar que los errores sean accesibles para lectores de pantalla
    • Confirmar que el foco se mueva al primer error

    Correcto

    <!-- Identificación clara de errores -->
    <form>
      <div class="form-field">
        <label for="email">Correo electrónico *</label>
        <input 
          type="email" 
          id="email" 
          name="email"
          aria-describedby="email-error"
          aria-invalid="true"
        >
        <span id="email-error" class="error" role="alert">
          Error: Por favor ingresa un correo electrónico válido (ejemplo: usuario@dominio.com)
        </span>
      </div>
      
      <!-- Resumen de errores al inicio -->
      <div role="alert" aria-live="assertive">
        <h2>Se encontraron 2 errores en el formulario:</h2>
        <ul>
          <li><a href="#email">Correo electrónico: formato inválido</a></li>
          <li><a href="#password">Contraseña: debe tener al menos 8 caracteres</a></li>
        </ul>
      </div>
    </form>

    Incorrecto

    <!-- Error no identificado claramente -->
    <form>
      <label for="email">Correo electrónico</label>
      <input type="email" id="email" style="border-color: red;">
      <!-- Solo indicación visual, sin texto -->
      
      <!-- Mensaje de error genérico -->
      <span class="error">Error en el formulario</span>
      <!-- No indica qué campo tiene error -->
    </form>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.3.2Etiquetas o instruccionesNivel AComprensibleAutomatizable

    Se proporcionan etiquetas o instrucciones cuando el contenido requiere entrada de datos por parte del usuario.

    Cómo verificarlo

    • Revisar todos los campos de formulario
    • Verificar que tengan etiquetas (<label>) asociadas
    • Confirmar que las instrucciones sean claras
    • Verificar que se indiquen campos requeridos
    • Confirmar que se expliquen formatos esperados

    Correcto

    <!-- Etiquetas e instrucciones claras -->
    <form>
      <div class="form-field">
        <label for="phone">
          Teléfono * 
          <span class="hint">(formato: 123-456-7890)</span>
        </label>
        <input 
          type="tel" 
          id="phone" 
          name="phone"
          required
          pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
          aria-describedby="phone-hint"
        >
        <span id="phone-hint" class="hint">
          Ingresa tu número de teléfono con guiones
        </span>
      </div>
      
      <div class="form-field">
        <label for="password">
          Contraseña *
        </label>
        <input 
          type="password" 
          id="password" 
          name="password"
          required
          aria-describedby="password-requirements"
        >
        <ul id="password-requirements" class="hint">
          <li>Mínimo 8 caracteres</li>
          <li>Al menos una mayúscula</li>
          <li>Al menos un número</li>
        </ul>
      </div>
      
      <p><span aria-label="requerido">*</span> Campos requeridos</p>
    </form>

    Incorrecto

    <!-- Sin etiquetas ni instrucciones -->
    <form>
      <input type="text" placeholder="Teléfono">
      <!-- Sin label, solo placeholder -->
      
      <input type="password">
      <!-- Sin indicación de requisitos -->
      
      <input type="text" required>
      <!-- Sin indicación de que es requerido -->
    </form>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.3.3Sugerencias ante erroresNivel AAComprensibleManual

    Si se detecta automáticamente un error en la entrada de datos y se conocen sugerencias para su corrección, entonces las sugerencias se proporcionan al usuario.

    Cómo verificarlo

    • Enviar formularios con errores
    • Verificar que se proporcionen sugerencias específicas
    • Confirmar que las sugerencias sean útiles y accionables
    • Verificar que no solo se indique el error, sino cómo corregirlo

    Correcto

    <!-- Sugerencias específicas -->
    <form>
      <div class="form-field">
        <label for="email">Correo electrónico</label>
        <input 
          type="email" 
          id="email" 
          name="email"
          aria-describedby="email-error"
          aria-invalid="true"
        >
        <span id="email-error" class="error" role="alert">
          Error: El correo electrónico debe incluir un símbolo @ y un dominio válido.
          Ejemplo: usuario@ejemplo.com
        </span>
      </div>
      
      <div class="form-field">
        <label for="date">Fecha de nacimiento</label>
        <input 
          type="date" 
          id="date" 
          name="date"
          aria-describedby="date-error"
          aria-invalid="true"
        >
        <span id="date-error" class="error" role="alert">
          Error: La fecha debe estar en formato DD/MM/AAAA.
          Ejemplo: 15/03/1990
        </span>
      </div>
    </form>

    Incorrecto

    <!-- Sin sugerencias -->
    <form>
      <label for="email">Correo electrónico</label>
      <input type="email" id="email" aria-invalid="true">
      <span class="error">Error: formato inválido</span>
      <!-- No explica cómo corregir -->
      
      <label for="password">Contraseña</label>
      <input type="password" id="password" aria-invalid="true">
      <span class="error">Contraseña incorrecta</span>
      <!-- No da sugerencias -->
    </form>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.3.4Prevención de errores (legales, financieros, datos)Nivel AAComprensibleManual

    Para páginas web que causan compromisos legales o transacciones financieras, se cumple al menos una de las siguientes: reversible, revisado, confirmado.

    Cómo verificarlo

    • Identificar formularios con transacciones importantes
    • Verificar que se pueda revisar antes de enviar
    • Confirmar que se solicite confirmación explícita
    • Verificar que se pueda cancelar o revertir
    • Probar compras, transferencias, eliminaciones de cuenta

    Correcto

    <!-- Proceso de compra con revisión -->
    <div class="checkout-flow">
      <!-- Paso 1: Carrito -->
      <div class="cart">
        <h2>Revisa tu pedido</h2>
        <ul>
          <li>Producto 1 - $100</li>
          <li>Producto 2 - $50</li>
        </ul>
        <p>Total: $150</p>
        <button onclick="goToCheckout()">Continuar al pago</button>
      </div>
      
      <!-- Paso 2: Confirmación -->
      <div class="confirmation">
        <h2>Confirma tu compra</h2>
        <p>Estás a punto de realizar una compra de $150</p>
        <label>
          <input type="checkbox" required>
          He revisado mi pedido y confirmo la compra
        </label>
        <button onclick="completePurchase()">Confirmar y pagar</button>
        <button onclick="goBack()">Volver al carrito</button>
      </div>
      
      <!-- Paso 3: Confirmación final -->
      <div class="final-confirmation">
        <h2>¿Estás seguro?</h2>
        <p>Esta acción cargará $150 a tu tarjeta</p>
        <button onclick="processPayment()">Sí, procesar pago</button>
        <button onclick="cancel()">No, cancelar</button>
      </div>
    </div>
    
    <!-- Eliminación de cuenta con confirmación -->
    <form onsubmit="return confirmDelete()">
      <h2>Eliminar cuenta</h2>
      <p>Esta acción es permanente y no se puede deshacer.</p>
      <label>
        <input type="checkbox" required>
        Entiendo que mi cuenta y todos mis datos serán eliminados permanentemente
      </label>
      <label for="confirm-text">
        Escribe "ELIMINAR" para confirmar:
      </label>
      <input type="text" id="confirm-text" required>
      <button type="submit">Eliminar mi cuenta</button>
    </form>

    Incorrecto

    <!-- Sin confirmación ni revisión -->
    <form onsubmit="deleteAccount()">
      <button type="submit">Eliminar cuenta</button>
    </form>
    
    <!-- Compra sin revisión -->
    <button onclick="purchase()">Comprar ahora</button>
    <!-- Procesa pago inmediatamente sin confirmación -->
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.3.7Entrada redundanteNivel AComprensibleManualNuevo en 2.2

    La información previamente ingresada por o proporcionada al usuario que se requiere nuevamente en el mismo proceso se auto-completa o está disponible para que el usuario la seleccione.

    Cómo verificarlo

    • Completar formularios de múltiples pasos
    • Verificar que no se pida la misma información dos veces
    • Confirmar que datos previos se auto-completen
    • Verificar que se ofrezcan opciones para reutilizar información
    • Probar procesos de checkout, registro, etc.

    Correcto

    <!-- Formulario multi-paso con datos guardados -->
    <form>
      <!-- Paso 1: Información personal -->
      <div class="step-1">
        <label for="name">Nombre completo</label>
        <input type="text" id="name" name="name" autocomplete="name">
        
        <label for="email">Correo electrónico</label>
        <input type="email" id="email" name="email" autocomplete="email">
      </div>
      
      <!-- Paso 2: Dirección de envío -->
      <div class="step-2">
        <h2>Dirección de envío</h2>
        <label>
          <input type="checkbox" onchange="copyBillingAddress()">
          Usar la misma dirección de facturación
        </label>
        
        <label for="shipping-address">Dirección</label>
        <input 
          type="text" 
          id="shipping-address" 
          name="shipping-address"
          autocomplete="shipping street-address"
        >
      </div>
      
      <!-- Paso 3: Confirmación (muestra datos sin pedir de nuevo) -->
      <div class="step-3">
        <h2>Confirma tus datos</h2>
        <dl>
          <dt>Nombre:</dt>
          <dd id="confirm-name"></dd>
          <dt>Email:</dt>
          <dd id="confirm-email"></dd>
          <dt>Dirección:</dt>
          <dd id="confirm-address"></dd>
        </dl>
        <button type="button" onclick="editInfo()">Editar información</button>
        <button type="submit">Confirmar</button>
      </div>
    </form>

    Incorrecto

    <!-- Pide la misma información múltiples veces -->
    <form>
      <!-- Paso 1 -->
      <label for="email1">Correo electrónico</label>
      <input type="email" id="email1" name="email1">
      
      <!-- Paso 2 - pide email de nuevo -->
      <label for="email2">Confirma tu correo electrónico</label>
      <input type="email" id="email2" name="email2">
      <!-- Sin autocompletar del paso anterior -->
      
      <!-- Paso 3 - pide email otra vez -->
      <label for="email3">Correo para notificaciones</label>
      <input type="email" id="email3" name="email3">
      <!-- Sin opción de reutilizar -->
    </form>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 3.3.8Autenticación accesible (mínimo)Nivel AAComprensibleHíbridoNuevo en 2.2

    No se usa una prueba de función cognitiva para ningún paso en un proceso de autenticación a menos que se proporcione una alternativa.

    Cómo verificarlo

    • Revisar todos los procesos de login/autenticación
    • Verificar que no requieran recordar información (contraseñas complejas sin gestor)
    • Confirmar que se permita copiar/pegar contraseñas
    • Verificar que se soporten gestores de contraseñas
    • Confirmar que no haya CAPTCHAs cognitivos sin alternativa

    Correcto

    <!-- Login accesible -->
    <form>
      <label for="email">Correo electrónico</label>
      <input 
        type="email" 
        id="email" 
        name="email"
        autocomplete="email"
      >
      
      <label for="password">Contraseña</label>
      <input 
        type="password" 
        id="password" 
        name="password"
        autocomplete="current-password"
      >
      <!-- Permite gestores de contraseñas y copiar/pegar -->
      
      <button type="submit">Iniciar sesión</button>
      
      <!-- Alternativas de autenticación -->
      <button type="button" onclick="loginWithBiometric()">
        Usar huella digital
      </button>
      <button type="button" onclick="loginWithPasskey()">
        Usar passkey
      </button>
      <button type="button" onclick="sendMagicLink()">
        Enviar enlace mágico por email
      </button>
    </form>
    
    <!-- CAPTCHA accesible -->
    <div class="captcha">
      <img src="captcha.png" alt="CAPTCHA visual">
      <button onclick="playAudioCaptcha()">
        Escuchar CAPTCHA en audio
      </button>
      <button onclick="useAlternativeVerification()">
        Verificar por email
      </button>
    </div>

    Incorrecto

    <!-- Login inaccesible -->
    <form>
      <label for="username">Usuario</label>
      <input 
        type="text" 
        id="username" 
        name="username"
        autocomplete="off"
        onpaste="return false"
      >
      <!-- Bloquea autocompletar y copiar/pegar -->
      
      <label for="password">Contraseña</label>
      <input 
        type="password" 
        id="password" 
        name="password"
        autocomplete="off"
        onpaste="return false"
      >
      
      <!-- Pregunta de seguridad cognitiva -->
      <label for="security">¿Cuál era el nombre de tu primera mascota?</label>
      <input type="text" id="security" name="security">
      <!-- Requiere recordar información sin alternativa -->
      
      <button type="submit">Iniciar sesión</button>
    </form>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 4.1.2Nombre, función y valorNivel ARobustoAutomatizable

    Para todos los componentes de interfaz de usuario, el nombre y la función pueden ser determinados por software; los estados, propiedades y valores que pueden ser establecidos por el usuario pueden ser establecidos por software; y la notificación de cambios a estos elementos está disponible para los agentes de usuario, incluyendo las tecnologías de asistencia.

    Cómo verificarlo

    • Inspeccionar todos los componentes interactivos
    • Verificar que tengan nombres accesibles apropiados
    • Confirmar que los roles ARIA sean correctos
    • Verificar que los estados se comuniquen (aria-expanded, aria-checked, etc.)
    • Usar lector de pantalla para verificar anuncios

    Correcto

    <!-- Botón con nombre y función claros -->
    <button aria-label="Cerrar ventana">
      <svg>...</svg>
    </button>
    
    <!-- Checkbox con estado -->
    <label>
      <input 
        type="checkbox" 
        id="agree"
        aria-checked="false"
      >
      Acepto los términos
    </label>
    
    <!-- Componente personalizado con ARIA -->
    <div 
      role="button"
      tabindex="0"
      aria-label="Reproducir video"
      aria-pressed="false"
      onclick="togglePlay()"
      onkeydown="if(event.key==='Enter') togglePlay()"
    >
      <svg>...</svg>
    </div>
    
    <!-- Acordeón con estados -->
    <button 
      aria-expanded="false"
      aria-controls="panel1"
      onclick="togglePanel()"
    >
      Sección 1
    </button>
    <div id="panel1" hidden>
      Contenido del panel
    </div>

    Incorrecto

    <!-- Sin nombre accesible -->
    <div onclick="closeWindow()">
      <svg>...</svg>
    </div>
    
    <!-- Sin comunicar estado -->
    <div class="checkbox" onclick="toggle()">
      <!-- Estado solo visual -->
    </div>
    
    <!-- Componente sin rol ni nombre -->
    <div onclick="doAction()">
      Acción
    </div>
    Documentación oficial W3C (se abre en una nueva pestaña)
  • 4.1.3Mensajes de estadoNivel AARobustoAutomatizable

    En contenido implementado usando lenguajes de marcado, los mensajes de estado pueden ser determinados por software a través de función o propiedades de tal manera que puedan ser presentados al usuario por tecnologías de asistencia sin recibir el foco.

    Cómo verificarlo

    • Identificar mensajes de estado (éxito, error, progreso, notificaciones)
    • Verificar que usen role='status' o role='alert'
    • Confirmar que usen aria-live apropiadamente
    • Verificar que no requieran foco para ser anunciados
    • Usar lector de pantalla para verificar anuncios

    Correcto

    <!-- Mensaje de éxito -->
    <div role="status" aria-live="polite">
      Formulario enviado exitosamente
    </div>
    
    <!-- Mensaje de error urgente -->
    <div role="alert" aria-live="assertive">
      Error: No se pudo guardar los cambios
    </div>
    
    <!-- Progreso de carga -->
    <div role="status" aria-live="polite" aria-atomic="true">
      Cargando... <span id="progress">50%</span> completado
    </div>
    
    <!-- Notificación -->
    <div role="status" aria-live="polite">
      Tienes 3 mensajes nuevos
    </div>
    
    <!-- Resultado de búsqueda -->
    <div role="status" aria-live="polite" aria-atomic="true">
      Se encontraron <span id="count">42</span> resultados
    </div>

    Incorrecto

    <!-- Sin role ni aria-live -->
    <div class="success-message">
      Formulario enviado
    </div>
    
    <!-- Mensaje que requiere foco -->
    <div tabindex="0" onfocus="announceMessage()">
      Mensaje importante
    </div>
    
    <!-- Sin anuncio para lectores de pantalla -->
    <div style="color: green;">
      ✓ Guardado
    </div>
    Documentación oficial W3C (se abre en una nueva pestaña)

Este catálogo es solo el punto de partida

Auditar 55 criterios a mano en cada página es lento. Nuestra plataforma ejecuta axe, Lighthouse e IBM Equal Access, gestiona campañas de auditoría, prioriza hallazgos y mide tu cumplimiento WCAG 2.2 y Ley 7600 en el tiempo.