W3docs

Consideraciones de Accesibilidad en el Desarrollo Web

La accesibilidad web es esencial para crear experiencias digitales inclusivas. Beneficia a usuarios con discapacidades y mejora la experiencia general del usuario.

Garantizar la accesibilidad web es fundamental para crear experiencias digitales inclusivas. La accesibilidad no solo beneficia a los usuarios con discapacidades, sino que también mejora la experiencia general del usuario y amplía el alcance de tu audiencia. Esta guía cubre la importancia de la accesibilidad, las técnicas para hacer accesible la manipulación del DOM, el papel de ARIA (Accessible Rich Internet Applications) y cómo mantener los widgets dinámicos de JavaScript utilizables por todos.

Cuando construyes interactividad con JavaScript — alternando contenido, seleccionando y actualizando elementos, o modificando el documento — asumes la responsabilidad de la accesibilidad que el navegador, de otro modo, proporcionaría de forma gratuita con HTML simple. Este capítulo muestra dónde recae esa responsabilidad y cómo cumplirla.

Creación de Contenido Accesible

Importancia de la Accesibilidad en el Desarrollo Web

La accesibilidad en el desarrollo web garantiza que todos los usuarios, incluidos aquellos con discapacidades, puedan acceder e interactuar con el contenido web de manera efectiva. La Organización Mundial de la Salud estima que más de 1.000 millones de personas viven con algún tipo de discapacidad. Al hacer accesible tu contenido web, llegas a una audiencia más amplia, mejoras la usabilidad y cumples con estándares legales como la Ley de Estadounidenses con Discapacidades (ADA) y las Pautas de Accesibilidad para el Contenido Web (WCAG).

Beneficios de la Accesibilidad

  1. Inclusividad: Permite a los usuarios con diversas discapacidades acceder a información y servicios.
  2. Mejora del SEO: Los motores de búsqueda suelen recompensar a los sitios web accesibles con mejores posiciones.
  3. Cumplimiento Legal: Ayuda a evitar posibles problemas legales relacionados con los estándares de accesibilidad.
  4. Usabilidad Mejorada: Mejora la experiencia general del usuario para todos los visitantes, incluidos aquellos sin discapacidades.

Técnicas para Hacer Accesible la Manipulación del DOM

Muchas personas no pueden usar un ratón — navegan con el teclado, un dispositivo de conmutación o un lector de pantalla que controla el teclado. Si un control solo responde a los clics, esos usuarios quedan excluidos. La regla general: todo lo que un usuario de ratón puede hacer, un usuario de teclado también debe poder hacerlo.

Asegúrate de que todos los elementos interactivos sean accesibles mediante el teclado. Confía en el orden natural del DOM para la navegación por tabulación y mantener un flujo lógico. El atributo tabindex controla esto:

  • tabindex="0" pone un elemento en el orden de tabulación natural (útil cuando haces interactivo un elemento no nativo).
  • tabindex="-1" lo elimina del orden de tabulación, pero te permite enfocarlo programáticamente con element.focus().
  • Los valores positivos como tabindex="3" anulan el orden natural y casi siempre causan confusión — evítalos.

Los elementos nativos como <button>, <a href> y los controles de formulario son enfocables con el teclado por defecto, lo cual es una de las razones más sólidas para preferirlos sobre <div>s con clics. Asegúrate siempre de que el indicador de enfoque visible (el contorno) tenga estilos para que los usuarios de teclado puedan ver claramente qué elemento está enfocado — nunca apliques outline: none sin proporcionar un reemplazo.

<!DOCTYPE html>
<html>
<head>
    <title>Keyboard Navigation Example</title>
</head>
<body>
<h4>Press the 'Tab' key to navigate through the buttons!</h4>
    <button>Button 1</button>
    <button>Button 2</button>
    <button>Button 3</button>
</body>
</html>

Este ejemplo se basa en el orden natural del DOM para los botones, lo que facilita la navegación a los usuarios de teclado.

Componentes Interactivos Accesibles

Este ejemplo demuestra cómo crear un acordeón accesible usando roles y propiedades ARIA, y gestionando el enfoque de manera eficaz.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Accessible Accordion Example</title>
    <style>
        .accordion {
            border: 1px solid #ccc;
            border-radius: 5px;
            margin: 20px 0;
        }
        .accordion-header {
            padding: 10px;
            cursor: pointer;
            background-color: #f0f0f0;
            border-bottom: 1px solid #ccc;
            width: 100%;
            text-align: left;
        }
        .accordion-content {
            display: none;
            padding: 10px;
        }
    </style>
</head>
<body>

<h1>Accessible Accordion Example</h1>
<h4>Use your keyboard (Enter or Space key) to toggle the accordion!</h4>

<div class="accordion">
    <button class="accordion-header" id="accordion-header-1" aria-controls="accordion-content-1" aria-expanded="false">
        Section 1
    </button>
    <div class="accordion-content" id="accordion-content-1" role="region" aria-labelledby="accordion-header-1" tabindex="-1">
        <p>This is the content of section 1.</p>
    </div>
</div>

<div class="accordion">
    <button class="accordion-header" id="accordion-header-2" aria-controls="accordion-content-2" aria-expanded="false">
        Section 2
    </button>
    <div class="accordion-content" id="accordion-content-2" role="region" aria-labelledby="accordion-header-2" tabindex="-1">
        <p>This is the content of section 2.</p>
    </div>
</div>

<div class="accordion">
    <button class="accordion-header" id="accordion-header-3" aria-controls="accordion-content-3" aria-expanded="false">
        Section 3
    </button>
    <div class="accordion-content" id="accordion-content-3" role="region" aria-labelledby="accordion-header-3" tabindex="-1">
        <p>This is the content of section 3.</p>
    </div>
</div>

<script>
    document.querySelectorAll('.accordion-header').forEach(header => {
        header.addEventListener('click', function () {
            const expanded = this.getAttribute('aria-expanded') === 'true';
            this.setAttribute('aria-expanded', !expanded);
            const content = document.getElementById(this.getAttribute('aria-controls'));
            content.style.display = !expanded ? 'block' : 'none';
        });

        header.addEventListener('keydown', function (event) {
            if (event.key === 'Enter' || event.key === ' ') {
                event.preventDefault();
                this.click();
            }
        });
    });
</script>

</body>
</html>
  • Estructura del Acordeón: El acordeón consiste en encabezados que, al hacer clic, expanden o contraen su contenido asociado.
  • HTML Semántico y ARIA:
    • Se usan elementos <button> nativos para los encabezados para garantizar compatibilidad integrada con el teclado y los lectores de pantalla.
    • aria-controls asocia los encabezados con su contenido.
    • aria-expanded indica el estado de la sección del acordeón.
    • role="region" en las secciones de contenido las identifica como regiones significativas.
  • Accesibilidad por Teclado:
    • Los controladores de eventos gestionan los eventos click y keydown para permitir alternar el acordeón mediante el teclado (Enter o Espacio).

Por qué esto importa:

  • Usabilidad Mejorada: El acordeón es utilizable con ratón y teclado.
  • Accesibilidad Mejorada: Los atributos ARIA comunican el estado y la estructura a las tecnologías de asistencia, haciéndolo accesible para los usuarios de lectores de pantalla.
  • Gestión del Enfoque: El enfoque permanece en el botón de activación, siguiendo los patrones estándar de acordeón y evitando saltos de navegación inesperados para los usuarios de teclado.

Para una cobertura más profunda sobre cómo conectar el comportamiento del teclado y los clics, consulta Manejo de eventos en el DOM.

HTML Semántico

Usa elementos HTML semánticos para transmitir el significado y la estructura del contenido. Esto ayuda a las tecnologías de asistencia a interpretar y navegar el contenido web de manera eficaz.

<!DOCTYPE html>
<html>
<head>
    <title>Semantic HTML Example</title>
</head>
<body>
    <header>
        <h1>Main Heading</h1>
    </header>
    <nav>
        <ul>
            <li><a href="#section1">Section 1</a></li>
            <li><a href="#section2">Section 2</a></li>
        </ul>
    </nav>
    <main>
        <section id="section1">
            <h2>Section 1</h2>
            <p>Content for section 1.</p>
        </section>
        <section id="section2">
            <h2>Section 2</h2>
            <p>Content for section 2.</p>
        </section>
    </main>
    <footer>
        <p>Footer content</p>
    </footer>
</body>
</html>

Este ejemplo usa elementos HTML semánticos como <header>, <nav>, <main>, <section> y <footer> para definir la estructura de la página.

Alternativas de Texto

Los lectores de pantalla no pueden interpretar imágenes, iconos ni dibujos en canvas — leen la alternativa de texto que tú proporcionas. Cada imagen significativa necesita un atributo alt que describa su contenido o función. Las imágenes decorativas que no aportan información deben tener un alt="" vacío para que el lector de pantalla las omita en lugar de anunciar un nombre de archivo.

<!-- Meaningful image: describe it -->
<img src="chart.png" alt="Sales rose 40% from January to March" />

<!-- Decorative image: hide it from screen readers -->
<img src="divider.png" alt="" />

<!-- Icon-only button: label it -->
<button aria-label="Close dialog">&times;</button>

Cuando generas imágenes o botones de iconos dinámicamente con JavaScript, establece el alt o aria-label al mismo tiempo que creas el elemento — nunca entregues un control sin etiquetar.

Gestión del Enfoque en Contenido Dinámico

Cuando JavaScript abre un diálogo, revela contenido nuevo o guía al usuario a través de un flujo de múltiples pasos, debes mover el enfoque de forma deliberada. De lo contrario, un usuario de teclado o lector de pantalla queda en la posición anterior sin saber que algo ha cambiado. El siguiente ejemplo abre un modal, mueve el enfoque a su interior, atrapa el enfoque para que Tab no pueda escapar y restaura el enfoque al botón de activación al cerrarse.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Accessible Modal Example</title>
    <style>
        .overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.5); }
        .overlay.open { display: flex; align-items: center; justify-content: center; }
        .dialog { background: #fff; padding: 20px; border-radius: 6px; min-width: 260px; }
    </style>
</head>
<body>
    <button id="open-btn">Open dialog</button>

    <div class="overlay" id="overlay">
        <div class="dialog" role="dialog" aria-modal="true" aria-labelledby="dialog-title">
            <h2 id="dialog-title">Confirm action</h2>
            <p>Are you sure you want to continue?</p>
            <button id="confirm-btn">Confirm</button>
            <button id="close-btn">Cancel</button>
        </div>
    </div>

    <script>
        const overlay = document.getElementById('overlay');
        const openBtn = document.getElementById('open-btn');
        const closeBtn = document.getElementById('close-btn');
        let lastFocused = null;

        function openDialog() {
            lastFocused = document.activeElement;       // remember the trigger
            overlay.classList.add('open');
            document.getElementById('confirm-btn').focus(); // move focus in
        }

        function closeDialog() {
            overlay.classList.remove('open');
            if (lastFocused) lastFocused.focus();        // restore focus
        }

        openBtn.addEventListener('click', openDialog);
        closeBtn.addEventListener('click', closeDialog);

        // Trap focus inside the dialog and close on Escape
        overlay.addEventListener('keydown', function (event) {
            if (event.key === 'Escape') { closeDialog(); return; }
            if (event.key !== 'Tab') return;

            const focusable = overlay.querySelectorAll('button');
            const first = focusable[0];
            const last = focusable[focusable.length - 1];

            if (event.shiftKey && document.activeElement === first) {
                event.preventDefault();
                last.focus();
            } else if (!event.shiftKey && document.activeElement === last) {
                event.preventDefault();
                first.focus();
            }
        });
    </script>
</body>
</html>

Puntos clave: role="dialog" y aria-modal="true" indican a la tecnología de asistencia que se trata de un modal, aria-labelledby le da un nombre accesible, el enfoque se mueve al abrirse y regresa al activador al cerrarse, y Tab/Shift+Tab ciclan dentro del diálogo en lugar de escapar hacia atrás. Para más información sobre el enfoque programático, consulta Enfoque: focus / blur.

ARIA (Accessible Rich Internet Applications)

Más sobre ARIA

Como has aprendido hasta ahora, ARIA (Accessible Rich Internet Applications) es un conjunto de atributos que se pueden añadir a los elementos HTML para mejorar la accesibilidad para los usuarios de tecnologías de asistencia como los lectores de pantalla. Los atributos ARIA ayudan a definir roles, propiedades y estados de los elementos, haciendo las aplicaciones web más accesibles.

La regla más importante de ARIA es: si ya existe un elemento HTML nativo con el comportamiento que necesitas, úsalo en lugar de recrearlo con ARIA. Un <button> siempre es mejor que <div role="button">, porque el botón nativo te proporciona activación por teclado, enfoque y semántica para lectores de pantalla sin ningún JavaScript. ARIA no añade ningún comportamiento — solo cambia cómo un lector de pantalla describe un elemento. Recurre a ARIA cuando ningún elemento nativo sea adecuado (pestañas personalizadas, deslizadores, vistas de árbol, regiones en vivo).

Uso de Atributos ARIA para Mejorar la Accesibilidad

Roles ARIA

Los roles ARIA definen el tipo de elemento, ayudando a las tecnologías de asistencia a comprender su propósito.

<div role="button" aria-pressed="false">Toggle</div>

Este elemento no interactivo usa el estado aria-pressed para indicar su estado de alternancia.

Propiedades y Estados ARIA

Las propiedades y estados ARIA proporcionan información adicional sobre los elementos.

<!DOCTYPE html>
<html>
<head>
    <title>ARIA Example</title>
</head>
<body>
    <div role="alert" id="live-region">
        <!-- Dynamic content goes here -->
    </div>

    <script>
        document.getElementById('live-region').textContent = "This is an important message.";
    </script>
</body>
</html>

Este ejemplo usa propiedades ARIA para crear una región en vivo que anuncia mensajes importantes de forma dinámica. Una región en vivo es un elemento cuyos cambios el lector de pantalla lee en voz alta automáticamente, sin que el usuario tenga que mover el enfoque hacia ella — ideal para actualizaciones de estado, errores de formulario o mensajes de chat.

Puedes controlar con qué urgencia se anuncia el cambio:

  • role="alert" (o aria-live="assertive") interrumpe al usuario de inmediato — resérvalo para errores y mensajes de tiempo crítico.
  • aria-live="polite" espera hasta que el usuario esté inactivo antes de anunciar — úsalo para estados no urgentes como "Artículo añadido al carrito".
<div aria-live="polite" id="status"></div>

<script>
    // Updating the text content triggers the announcement
    document.getElementById('status').textContent = 'Settings saved.';
</script>

El elemento de región en vivo debe existir ya en el DOM antes de actualizarlo; si inyectas el elemento y su texto al mismo tiempo, muchos lectores de pantalla perderán el cambio.

Buenas Prácticas

  1. Usa HTML Semántico: Prefiere siempre los elementos HTML semánticos para proporcionar un significado y estructura claros al contenido.
  2. Implementa Accesibilidad por Teclado: Asegúrate de que todos los elementos interactivos puedan accederse y operarse mediante el teclado.
  3. Gestiona el Enfoque de Forma Eficaz: Controla el enfoque programáticamente para guiar a los usuarios a través de los cambios de contenido dinámico.
  4. Usa ARIA con Criterio: Aplica roles, propiedades y estados ARIA para mejorar, no reemplazar, la semántica de los elementos HTML nativos.
  5. Prueba con Tecnologías de Asistencia: Prueba regularmente tus aplicaciones web con lectores de pantalla y otras tecnologías de asistencia para garantizar la accesibilidad.
  6. Usa Herramientas de Prueba Automatizada: Ejecuta verificaciones con herramientas como axe o Lighthouse para detectar problemas comunes de accesibilidad de forma temprana.
Información

Asegúrate siempre de que tus modales y otros elementos dinámicos sean accesibles gestionando el enfoque de forma eficaz. Usa JavaScript para atrapar el enfoque dentro de los modales, ciclando a través de los elementos enfocables con la tecla Tab para evitar que los usuarios de teclado naveguen fuera del diálogo sin querer. Esto mejora la accesibilidad y proporciona una mejor experiencia de usuario.

Temas Relacionados

Conclusión

La accesibilidad es un aspecto fundamental del desarrollo web que garantiza que tu contenido sea utilizable por todas las personas, independientemente de sus capacidades. Al crear contenido accesible, usar técnicas para hacer accesible la manipulación del DOM y aprovechar los atributos ARIA, puedes mejorar significativamente la inclusividad y usabilidad de tus aplicaciones web. Implementar estas prácticas no solo ayuda a cumplir con los estándares legales, sino que también mejora la experiencia general del usuario.

Práctica

Práctica
¿Cuáles de las siguientes son consideraciones importantes para garantizar la accesibilidad en el desarrollo web?
¿Cuáles de las siguientes son consideraciones importantes para garantizar la accesibilidad en el desarrollo web?
Práctica
Cuando se abre un diálogo modal de JavaScript, ¿qué debes hacer para los usuarios de teclado y lectores de pantalla?
Cuando se abre un diálogo modal de JavaScript, ¿qué debes hacer para los usuarios de teclado y lectores de pantalla?
Práctica
¿Cuál es la primera regla de ARIA?
¿Cuál es la primera regla de ARIA?
Was this page helpful?