Atributo Tabindex y su efecto en la accesibilidad

El atributo tabindex forma parte de HTML y permite modificar la forma en la que un elemento recibe el foco del teclado. Su uso puede mejorar la accesibilidad de una interfaz, pero también puede empeorarla si se utiliza para corregir problemas que deberían resolverse con una estructura HTML adecuada.
La navegación con teclado es una parte esencial de la accesibilidad web. Muchas personas no utilizan ratón, bien porque trabajan con lector de pantalla, porque emplean otros productos de apoyo o porque simplemente prefieren desplazarse por la interfaz mediante la tecla de tabulación y otros comandos del teclado. En esos casos el foco indica en qué elemento se encuentra la interacción en cada momento.
Los elementos de HTML ya forman parte del orden de tabulación por defecto. Un enlace con href, un botón, un campo de formulario o un control nativo pueden recibir el foco sin necesidad de añadir atributos adicionales. Esto es importante porque HTML ya incorpora mucho comportamiento accesible cuando se utiliza correctamente.
El problema aparece cuando se intenta forzar el comportamiento de una página mediante tabindex sin tener en cuenta las expectativas de las personas que navegan con teclado.

Qué hace tabindex

El atributo tabindex permite alterar el orden natural del foco. Puede hacer que un elemento no interactivo pueda recibir el foco, puede retirar un elemento interactivo del orden de tabulación y también puede reorganizar el orden en el que se recorren los elementos de la página.
Su valor es numérico. Cuando se utiliza tabindex=»-1″, el elemento puede recibir el foco mediante JavaScript, pero no queda incluido en la navegación secuencial con la tecla Tab. Cuando se utiliza tabindex=»0″, el elemento entra en el orden de tabulación respetando la posición que ocupa en el código HTML. Cuando se utiliza un valor positivo, como tabindex=»1″ o tabindex=»2″, se fuerza un orden de navegación distinto al orden natural del documento.
En la práctica, los valores positivos suelen ser una mala señal. Si el orden de foco no coincide con el orden visual o lógico de la página, lo correcto normalmente no es añadir números para reconstruir artificialmente la navegación. Lo adecuado es revisar la estructura del HTML y utilizar CSS para ajustar la presentación visual cuando sea necesario.

<a href="/inicio">Inicio</a>
<div tabindex="0">Contenido desplazable</div>
<a href="/contacto">Contacto</a>

En este ejemplo, el div entra en el orden de tabulación en el lugar que ocupa dentro del documento. Esto puede ser correcto si ese contenedor tiene algún comportamiento interactivo real. Pero si se trata solo de un bloque de texto, añadirlo al foco puede introducir ruido innecesario en la navegación.

El foco no debe sustituir a la semántica

Una regla sencilla para evaluar el uso de tabindex consiste en preguntarse si el elemento debería ser interactivo. Si se necesita un botón, se debe utilizar un elemento button. Si se necesita un enlace, se debe utilizar un enlace. Si se necesita un campo de formulario, se debe utilizar el control correspondiente.

Crear un botón con un div y añadirle tabindex=»0″ no convierte ese elemento en un botón completo. Puede recibir el foco, pero no incorpora automáticamente el comportamiento esperado con teclado, la semántica adecuada ni la comunicación correcta con los productos de apoyo. En muchos casos, ese tipo de solución obliga a reproducir manualmente características que HTML ya ofrece de forma nativa.

La accesibilidad no consiste solo en que algo pueda recibir el foco. También importa qué anuncia el lector de pantalla, qué teclas activan el componente, cómo se informa del estado, cómo se integra en el flujo del documento y si la interacción coincide con lo que la persona usuaria espera.

Cuándo puede ser útil tabindex=”-1”

El valor -1 resulta útil cuando un elemento no debe aparecer en la navegación normal con Tab, pero necesita recibir el foco en una situación concreta. Un caso habitual es un mensaje de error después de enviar un formulario.

Si una persona envía un formulario y existen errores, mover el foco al resumen de errores puede ayudar a comprender qué ha ocurrido. Para una persona que navega con teclado, evita tener que volver a recorrer toda la página hasta localizar el problema. Para una persona que utiliza lector de pantalla, permite que el mensaje sea anunciado en el momento adecuado.

<div id="errores" tabindex="-1">
Hay errores en el formulario. Revisa los campos indicados.
</div>

Después, mediante JavaScript, se puede enviar el foco a ese elemento cuando se detecten errores.

document.getElementById('errores').focus();

Este patrón también puede ser útil en ventanas modales, paneles que se abren dinámicamente o zonas de la interfaz que aparecen como consecuencia de una acción de la persona usuaria. El objetivo no es añadir más paradas al teclado, sino colocar el foco en un punto lógico cuando cambia el contexto de interacción.

Cuándo puede ser útil tabindex=“0”

El valor 0 debe utilizarse con más cuidado. Su función es incorporar un elemento al orden natural de tabulación. Esto puede tener sentido cuando existe una zona que debe poder recibir interacción con teclado, pero que por defecto no forma parte del orden de foco.

Un ejemplo frecuente son los contenedores con desplazamiento interno creados con CSS mediante overflow.

Si un bloque tiene contenido desplazable y una persona solo utiliza el teclado, necesita poder situar el foco en esa región para desplazarse por ella. En ese caso, tabindex=»0″ puede hacer que el contenedor sea alcanzable saltando con la tecla de tabulador.

<section aria-labelledby="condiciones" tabindex="0" style="overflow: auto; max-height: 12rem;">
<h2 id="condiciones">Condiciones de uso</h2>
<p>Texto de las condiciones de uso...</p>
</section>

En este tipo de componentes no es suficiente con hacer que el contenedor reciba el foco. También conviene proporcionar una etiqueta accesible y una estructura semántica clara. Una persona que usa lector de pantalla debe poder entender qué contiene esa región y por qué ha llegado hasta ella.

Los valores positivos rompen expectativas

Los valores positivos de tabindex permiten definir un orden de tabulación independiente del orden del documento.

Esta práctica debe realizarse con mucho cuidado ya que es muy sencillo romper el orden coherente y comprensible del orden de tabulación.

Cuando el foco salta de una parte a otra de la página en un orden inesperado, la interfaz se vuelve más difícil de comprender. La persona que navega con teclado puede perder la relación entre la posición visual, la estructura del contenido y el punto real de interacción. Para quien utiliza lector de pantalla, esa separación entre orden del código, orden visual y orden de foco puede resultar especialmente confusa.

<div tabindex="3">Tercer elemento</div>
<div tabindex="1">Primer elemento</div>
<div tabindex="2">Segundo elemento</div>

Este código fuerza una secuencia que no coincide con el orden del documento. Si el diseño necesita mostrar visualmente los elementos de otra manera, CSS debería encargarse de la presentación. El HTML debe conservar un orden lógico, comprensible y coherente.

Componentes personalizados

Existen componentes interactivos que no tienen una equivalencia directa en HTML nativo. Un sistema de pestañas, determinados widgets complejos o algunos controles de aplicación pueden requerir una gestión específica del foco.

En estos casos, tabindex puede formar parte de la solución, pero no debe utilizarse de forma aislada. Un patrón de pestañas accesible, por ejemplo, puede necesitar que la pestaña activa tenga tabindex=»0″ y que las pestañas inactivas tengan tabindex=»-1″ para permitir una navegación controlada con flechas y una gestión correcta del foco.

Revisar el uso de tabindex

Una revisión de accesibilidad debería incluir la búsqueda de usos de tabindex en el código. Cada aparición merece una comprobación concreta. Si un elemento nativo interactivo tiene tabindex=»0″, probablemente no lo necesita. Si un elemento no interactivo tiene tabindex=»0″, conviene revisar si realmente debe recibir el foco. Si aparece un valor positivo, normalmente debería corregirse el orden del documento en lugar de mantener ese valor.

También es importante revisar los casos con tabindex=»-1″. No son necesariamente incorrectos, pero deben estar asociados a una gestión del foco clara. Si ningún script envía el foco a ese elemento, puede que el atributo no esté cumpliendo ninguna función.

Las herramientas automáticas pueden localizar estos casos, pero la decisión final requiere criterio humano. Una herramienta puede indicar que existe un tabindex, pero no siempre puede determinar si su uso responde a una necesidad real de interacción.

Una herramienta que debe usarse con criterio

tabindex no es un atributo prohibido. Es una herramienta potente para gestionar el foco en situaciones concretas. Pero precisamente por afectar directamente a la navegación con teclado, debe utilizarse con prudencia.

En una página bien estructurada, la mayor parte del orden de tabulación debería venir dado por el propio HTML. Los enlaces, botones y campos de formulario ya tienen comportamiento accesible cuando se usan correctamente. Añadir tabindex sin una razón clara puede introducir barreras donde antes no las había.

The Color Contrast Checker

El proyecto The Color Contrast Checker es una herramienta web orientada a revisar el contraste entre colores y facilitar el cumplimiento de las pautas de accesibilidad relacionadas con la legibilidad visual. Su objetivo principal es permitir que diseñadores, desarrolladores y responsables de contenido comprueben si una combinación de color de texto y fondo alcanza los niveles exigidos por WCAG para los criterios AA y AAA.

La propia herramienta se presenta como un comprobador gratuito de contraste WCAG con sugerencias para encontrar combinaciones de color accesibles.

El contraste de color es uno de esos aspectos de la accesibilidad que puede parecer sencillo hasta que se analiza con cierta atención. No es suficiente con que dos colores parezcan diferentes en una pantalla concreta, con un brillo concreto y en unas condiciones de iluminación concretas. Una combinación que para una persona resulta aceptable puede ser insuficiente para otra con baja visión, daltonismo, fatiga visual o simplemente utilizando el dispositivo en un entorno poco favorable.

La accesibilidad visual no depende únicamente del tamaño de la letra ni de la calidad tipográfica. También depende de la relación entre el color del primer plano y el color del fondo. Cuando esa relación de contraste de color es baja, el contenido puede seguir estando técnicamente presente, pero deja de ser cómodo, eficiente o incluso posible de leer para gran parte de los usuarios. En esa situación el problema deja de ser estético para convertirse en un problema funcional.

Herramientas como The Color Contrast Checker ayudan a convertir una percepción subjetiva en un dato verificable. El diseñador puede introducir los colores, comprobar la relación de contraste y conocer si la combinación cumple o no los umbrales establecidos. Esta verificación resulta especialmente útil porque evita depender únicamente de la intuición, de la vista del diseñador o de la apariencia en una única pantalla.

WCAG utiliza ratios de contraste para determinar si un texto resulta suficientemente distinguible respecto a su fondo. En el modelo tradicional de WCAG 2, la escala va de 1:1, cuando no hay contraste, hasta 21:1, que corresponde al contraste máximo entre negro y blanco. Otras herramientas actuales también incorporan APCA, un modelo perceptual propuesto en el contexto de WCAG 3, que expresa el contraste mediante valores de luminancia percibida en lugar de utilizar el ratio clásico.

La revisión del contraste no debería considerarse una fase final del proyecto. Debería formar parte del diseño desde el principio. Si una paleta no permite combinaciones suficientes para texto normal, texto grande, componentes interactivos y estados de interfaz, el problema no está en la herramienta que lo detecta. El problema está en la definición de la propia paleta.

También conviene recordar que una buena puntuación de contraste no resuelve por sí sola toda la accesibilidad visual. Un texto puede tener contraste suficiente y seguir siendo difícil de leer por usar un tamaño demasiado pequeño, una fuente poco clara, demasiado espaciado negativo, bloques extensos sin estructura o información transmitida solamente mediante color.

Introducción a Javascript

Cuando abrimos una página web en el navegador, éste interpreta el código HTML para entender qué contenido hay y qué significa cada parte. Después aplica el CSS para definir el aspecto visual de ese contenido. Pero una página web moderna no solo necesita estructura y presentación: en muchos casos también necesita comportamiento, lógica e interacción. Ahí es donde entra JavaScript.

JavaScript es el lenguaje que permite que una página web responda a acciones del usuario, modifique contenidos, valide formularios, cargue información sin recargar toda la página o cambie el estado de distintos elementos de la interfaz. Es, por tanto, la parte de la Web que aporta funcionalidad y dinamismo.

Qué es JavaScript

JavaScript es un lenguaje de programación. A diferencia de HTML y CSS, que no son lenguajes de programación, Javascript sí puede ejecutar comandos y funciones de lógica. Esto no implica que Javascript no tenga que relacionarse con HTML o CSS. Con HTML describimos el contenido y su estructura. Con CSS definimos la presentación visual. Con JavaScript programamos el comportamiento de la página.

Dónde se puede usar Javascript

Aunque mucha gente identifica JavaScript solo con el navegador, el lenguaje también se puede utilizar fuera de la Web en otros entornos como scripts en la Terminal de Linux o MacOçS, como lenguaje de programación para servidores con NodeJS o para programar servicios para la Nube.

El estándar del lenguaje se denomina ECMAScript, y JavaScript es su implementación más conocida en la actualidad.

Ejemplo básico en JavaScript

A continuación tenemos un ejemplo de una página HTML con un botón y un pequeño fragmento de JavaScript:

<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Mi primera página con JavaScript</title>
</head>
<body>
<h1>Mi primera página con JavaScript</h1>
<p id="mensaje">Todavía no ha pasado nada.</p>
<button id="boton">Pulsa aquí</button>

<script>
document.getElementById("boton").addEventListener("click", function () {
document.getElementById("mensaje").textContent = "Has pulsado el botón.";
});
</script>
</body>
</html>

Si guardamos ese contenido en un fichero con extensión .html y lo abrimos con el navegador, veremos una página con un botón. Al pulsarlo, el texto del párrafo cambiará.

Ese cambio no lo hace HTML ni lo hace CSS. Lo hace JavaScript.

Qué está ocurriendo en el ejemplo

Aunque a primera vista pueda parecer mucho código, en realidad están pasando pocas cosas.

Primero tenemos este párrafo:

<p id="mensaje">Todavía no ha pasado nada.</p>

Ese párrafo tiene un atributo id con el valor mensaje. Ese identificador nos permite localizar el elemento desde JavaScript.

Después tenemos este botón:

<button id="boton">Pulsa aquí</button>

También tiene un id, en este caso boton.

Y por último aparece el bloque script:

<script>
document.getElementById("boton").addEventListener("click", function () {
document.getElementById("mensaje").textContent = "Has pulsado el botón.";
});
</script>

Ese bloque contiene código JavaScript que el navegador ejecuta. La instrucción busca el botón, escucha el evento de pulsación (click) y, cuando ese evento ocurre, modifica el texto del párrafo.

La etiqueta <script>

La forma más habitual de incluir JavaScript en una página HTML es mediante la etiqueta <script>.

Puede escribirse directamente dentro del propio documento HTML:

<script>
console.log("Hola desde JavaScript");
</script>

O bien enlazarse desde un fichero externo:

<script src="app.js"></script>

En la práctica, cuando el código crece, lo normal es utilizar un fichero independiente. Esto facilita el mantenimiento, permite reutilizar código y evita mezclar demasiadas responsabilidades en el HTML.

JavaScript y el DOM

Cuando JavaScript trabaja con una página HTML, normalmente no “ve” el fichero como texto plano, sino como una estructura interna que el navegador ha construido en memoria.

A esa representación se la suele llamar DOM (Document Object Model).

Utilizando el DOM, JavaScript puede realizar diversas funciones como buscar y manipular elementos de la página, añadir y eliminar elementos, reaccionar a eventos provocados por el usuario o por el navegador…

JavaScript no sustituye a HTML

Una idea importante al empezar es que JavaScript no debería utilizarse para suplir una mala estructura HTML.

Primero conviene tener un documento HTML bien organizado y semántico. Después CSS se ocupa de la presentación. Y finalmente JavaScript añade comportamiento.

Si se invierte ese orden, es fácil terminar con páginas difíciles de mantener, menos accesibles y más frágiles.

En artículos anteriores indicamos que HTML describe contenido y CSS describe presentación. Siguiendo esa idea de separar contenido, diseño y funcionalidad, Javascript debe añadir funcionalidad sin romper la semántica del documento. Esta separación de responsabilidades hace que la página sea más clara, con un mejor mantenimiento y más robusta.

JavaScript no debe ser intrusivo ni imprescindible

Aunque JavaScript aporta mucha potencia a una página web, conviene usarlo con cierta prudencia.

Una mala práctica bastante común consiste en construir páginas que dependen completamente de JavaScript para funcionar, incluso en tareas básicas como mostrar contenido, seguir enlaces o enviar un formulario. Cuando esto ocurre, la página se vuelve dependiente de Javascript y, en muchos casos, menos accesible.

Lo apropiado es que HTML proporcione una base sólida por sí mismo. Es decir, que la estructura del documento, los enlaces, los textos y la información principal existan ya en el marcado. Después, JavaScript puede enriquecer esa base con comportamiento adicional: validar datos en el navegador, mostrar u ocultar partes de la interfaz, actualizar contenidos o responder a acciones del usuario.

Con esto se mantiene la idea de que JavaScript debería mejorar la experiencia, no convertirse en un obstáculo.

También conviene evitar un uso intrusivo del lenguaje. Por ejemplo, no es buena idea abrir ventanas inesperadas, cambiar el foco sin necesidad, alterar el contenido de manera brusca sin avisar o interceptar comportamientos normales del navegador si no hay un motivo claro. Todas esas prácticas pueden desorientar a muchas personas usuarias y hacer que la navegación resulte confusa.

Introducción a CSS

Cuando abrimos una página web en el navegador, éste interpreta el código HTML para entender qué contenido hay y qué significa cada parte (títulos, párrafos, enlaces, formularios, etc.).

Además de estructura y semántica, una página necesita presentacióny estilo visual (tipografías, tamaños, colores, márgenes, alineación, distribución en columnas, etc).

En los artículos sobre HTML se ha hablado de contenido, semántica y estructura pero nunca hablamos de aspecto visual o diseño. Esto se debe a que HTML, en las versiones más modernas y responsables con la accesibilidad, ha cedido toda la responsabilidad de definir el aspecto visual del contenido a la parte CSS de una página web.

Qué es CSS

CSS son las siglas de Cascading Style Sheets (Hojas de estilo en cascada).

Al igual que ocurre con HTML, CSS no es un lenguaje de programación. No ejecuta lógica como lo haría JavaScript; en su lugar, define reglas de estilo que el navegador aplica sobre los elementos HTML para controlar cómo se muestran en la pantalla.

La idea fundamental es separar responsabilidades entre las distintas partes de una página web. El código HTML describe el contenido y su estructura. El código CSS describe el aspecto visual y parte del comportamiento de presentación (por ejemplo, el diseño adaptable o ciertas animaciones). Por último, el código Javascript describe la funcionalidad y el dinamismo de la página.

Ejemplo básico en CSS

Un ejemplo típico es tener un fichero HTML y, aparte, un fichero CSS enlazado. Por ejemplo, un HTML clásico es:

<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Mi primera página con CSS</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Mi primera página</h1>
<p>Este es un párrafo con información.</p>
<a href="https://programaraciegas.net">Visitar el blog</a>
</body>
</html>

Y el contenido del fichero styles.css podría ser:

body {
font-family: system-ui, sans-serif;
line-height: 1.5;
}

h1 {
font-size: 2rem;
}

a {
text-decoration: underline;
}

Si guardamos ambos ficheros en la misma carpeta y abrimos el HTML en el navegador, veremos que el contenido es el mismo, pero con el aspecto definido por las reglas CSS.

Por qué estilos en cascada

El término cascading (en cascada) tiene una razón por la forma de aplicarse los estilos en un contenido. Cuando varias reglas podrían aplicarse al mismo elemento, CSS define un sistema para resolver conflictos (origen, orden, especificidad, importancia). 

Partes de una regla CSS

La unidad básica de CSS es la regla (a veces llamada ruleset). Una regla se compone de:

• Un selector, que indica a qué elementos se aplica.
• Un bloque de declaraciones, que indica qué propiedades se aplican y con qué valores.

Veamos un ejemplo simple:

p {
font-size: 1rem;
margin-bottom: 1rem;
}

En este caso:
• p es el selector: selecciona todos los párrafos.
• Dentro de { … } hay declaraciones.
• Cada declaración es un par propiedad: valor; como font-size: 1rem;.

Cómo se aplica CSS a una página web

Hay tres formas habituales de aplicar CSS:

Hoja de estilo externa

Es la forma más común y la recomendada por accesibilidad. Se enlaza desde el <head> de la página:

<link rel="stylesheet" href="styles.css">

Entre las ventajas encontramos la separación del diseño del contenido y permite reutilizar estilos en muchas páginas.

Estilos internos

Se escriben dentro de un bloque <style> en el <head>:

<style>
p { line-height: 1.6; }
</style>

Esto es útil para ejemplos o páginas muy pequeñas, pero no es reutilizable para otras páginas.

Estilos en línea

Se escriben directamente en el atributo style de un elemento del <body>: dentro de la estructura de contenidos de la página.

<p style="line-height: 1.6;">Texto</p>

Aunque este estilo se aplica al contenido, es la opción menos recomendable porque mezcla contenido y presentación y complica el mantenimiento de la página y su estructura.

Los selectores CSS

El selector es la condición que decide qué elementos reciben una regla. 
Los más utilizados son:

Selector por etiqueta

Afecta a todos los elementos de ese tipo:

p { ... }
h1 { ... }

Selector por clase

Afecta a elementos que tengan class=»…»:

.destacado { font-weight: bold; }

Y en HTML:

<p class="destacado">Texto importante</p>

Selector por id

Afecta a un único elemento con id=»…»:

#cabecera { ... }

En HTML:

<header id="cabecera">...</header>

En la práctica, para estilos suele preferirse clases antes que abusar de id, porque son más reutilizables en otros contenidos o componentes.

La cascada: qué pasa cuando hay conflicto

Es habitual que varias reglas intenten aplicar estilos al mismo elemento. CSS resuelve esto con la aplicación en cascada: el navegador decide qué declaración gana según el origen y el orden, y si hace falta entra en juego la especificidad del selector. 

Un ejemplo típico que nos podemos encontrar es:

p { color: black; }
.destacado { color: blue; }

Si un párrafo tiene class=»destacado», el color será azul porque .destacado es más específico que p.

La cascada es una de las razones por las que, al empezar con CSS, a veces parece que no se aplique correctamente a algunos contenidos. normalmente sí funciona, pero otra regla está ganando en prevalencia de la cascada.

Accesibilidad y CSS

CSS puede mejorar mucho la experiencia de navegación y la accesibilidad presente en la página web o romperla con facilidad. Un mal CSS es responsable de estas barreras de accesibilidad:

  • Contraste de color insuficiente entre texto y fondo. 
  • Eliminar el foco del teclado por estética. Evita hacer outline: none; sin ofrecer una alternativa visible.
  • No respetar preferencias del usuario, como reducir animaciones con prefers-reduced-motion. 
  • Uso de tipografía ilegible o no adaptable a las necesidades del usuario.

Estructurar el contenido textual en un documento HTML

Cuando una página HTML tiene una organización  por zonas(landmarks, secciones y encabezados), con la definición del mapa general para navegar, es necesario profundizar más en la organización de los contenidos textuales buscando cómo escribir HTML que se entienda bien tanto visualmente como con lector de pantalla, y que además sea fácil de mantener.

Semántica antes que estilo

Una idea que conviene repetir siempre es que en HTML no se dibuja la página, se describe qué es cada cosa.

El CSS se encarga de cómo se ve.

El objetivo con HTML es que el contenido tenga una estructura que se pueda comprender incluso si no hay estilos visuales, se navega por teclado o con lector de pantallas o se está accediendo desde un dispositivo móvil o de escritorio. 

Párrafos

El párrafo es la unidad mínima de texto con sentido propio. Si se está escribiendo frases que forman una idea, normalmente eso es un <p>.

Ejemplo

<p>HTML es un lenguaje de marcado. Su objetivo es describir el contenido de una página.</p>
<p>Cuando usamos elementos semánticos, hacemos que la web sea más navegable y accesible.</p>

Errores habituales

Muchos desarrolladores suelen usar <br> para construir párrafos pero <br> se debe utilizar para un salto de línea dentro de un mismo bloque, por ejemplo direcciones postales o poesía, no para separar ideas completas.

Un mal ejemplo puede ser:

HTML es un lenguaje de marcado.<br>
Su objetivo es describir el contenido de una página.<br><br>
Cuando usamos elementos semánticos...

Otro error habitual es meter párrafos dentro de cualquier cosa porque funciona en el navegador. Por ejemplo, meter texto plano directamente dentro de un contenedor sin estructura. Se puede, pero se pierde semántica y consistencia.

Listas

Una lista no es solo un párrafo con viñetas bonitas: es una relación estructural entre elementos semánticamente relacionados de forma consecutiva.

Listas no ordenadas: <ul>

Se deben utilizar para elementos sin orden relevante.

<ul>
<li>Texto alternativo</li>
<li>Encabezados jerárquicos</li>
<li>Landmarks</li>
</ul>

Listas ordenadas: <ol>

Se deben utilizar cuando el orden importa (pasos, ranking, instrucciones).

<ol>
<li>Abre el archivo HTML.</li>
<li>Localiza el contenido principal.</li>
<li>Revisa la jerarquía de encabezados.</li>
</ol>

Listas de definición: <dl>

Se deben utilizar para pares término–definición. Son muy útiles en glosarios o fichas.

<dl>
<dt>Landmark</dt>
<dd>Región navegable de una página (main, nav, footer...).</dd>

<dt>Semántica</dt>
<dd>El significado estructural de un elemento HTML.</dd>
</dl>

Errores habituales

Alguno de los errores más comunes a la hora de agrupar contenidos en lista es, por ejemplo, simular listas con <p>• …</p>: visualmente se parece, pero para la accesibilidad no es una lista.
Otros de los errores es usar listas para maquetar (por ejemplo, columnas) cuando en realidad no se está representando un conjunto de elementos relacionados.

Citas

Las citas también son marcas semánticas que ayudan a estructurar mejor el contenido textual. Existen los siguientes marcados de cita:

Cita en línea: <q> utilizada para una cita corta dentro de una frase.

<p>Como dijo alguien una vez: <q>la accesibilidad es usabilidad para todos</q>.</p>

Cita en bloque: <blockquote> utilizada para un fragmento más largo que merece entidad propia o que ocupa más de un párrafo.

<blockquote>
<p>La accesibilidad no es una característica extra. Es parte del diseño.</p>
</blockquote>

Se puede añadir la fuente de forma clara usando <cite> (no es el enlace, es la referencia bibliográfica):

<blockquote>
<p>La accesibilidad no es una característica extra. Es parte del diseño.</p>
<cite>Manual interno del equipo</cite>
</blockquote>

Errores habituales

Se suele usar <blockquote> solo para poner texto sangrado. Eso es CSS.
• Poner comillas visuales y olvidarte de la estructura: el lector de pantalla no sabe que es una cita.

Código: <code>, <pre>, <kbd>, <samp> (sí, hay más de uno)

El contenido técnico es especialmente sensible a accesibilidad y comprensión.

Código en línea: <code>

Para pequeños fragmentos dentro de un párrafo.

<p>El elemento <code>&lt;main&gt;</code> debe aparecer una sola vez por página.</p>

Bloques de código: <pre><code>

Cuando necesitas respetar espacios y saltos de línea.

<pre><code>function hello() {
console.log(Hola);
}</code></pre>

Teclas y atajos: <kbd>

Para representar lo que el usuario pulsa.

<p>Pulsa <kbd>Control</kbd> + <kbd>S</kbd> para guardar.</p>

Salida del sistema: <samp>

Para texto que representa la salida de un programa, terminal, etc.

<p>El sistema mostrará: <samp>Error: file not found</samp></p>

Buenas prácticas muy recomendables:
• Escapa caracteres en código (&lt;, &gt;, &amp;) si estás escribiendo HTML dentro del bloque.
• Si publicas tutoriales, intenta que el texto explique el código antes y después: el bloque de código sin contexto es una pared.

Tablas: solo para datos, y con estructura real

La tabla es el elemento que más se malusa.

Regla de oro:

Una tabla es para datos tabulares, no para maquetar.

¿Cuándo sí usar tabla?

Cuando tienes datos que se entienden por filas/columnas: horarios, comparativas, listados con atributos, etc.

Ejemplo básico con cabecera:

<table>
<caption>Comparativa de planes</caption>
<thead>
<tr>
<th scope=col>Plan</th>
<th scope=col>Precio</th>
<th scope=col>Soporte</th>
</tr>
</thead>
<tbody>
<tr>
<td>Básico</td>
<td>0 €</td>
<td>No</td>
</tr>
<tr>
<td>Pro</td>
<td>10 €</td>
<td>Sí</td>
</tr>
</tbody>
</table>

Claves de accesibilidad:
• <caption>: describe la tabla. Muchísima gente lo olvida.
• <th> con scope=col o scope=row: define encabezados de columna o fila.
• Usa <thead>, <tbody> cuando tenga sentido: ayuda a organizar.

Errores típicos que rompen la experiencia:
• Tablas sin encabezados: el lector de pantalla leerá celdas sin contexto.
• Tablas para alinear cosas (como un grid de diseño): hoy eso es CSS (flex, grid).

¿Cuándo NO usar un <div>?

El <div> es un contenedor genérico sin semántica. No es malo, pero es la última opción, no la primera.

Usa <div> cuando:
• necesitas agrupar elementos para aplicar estilos o layout,
• y no hay un elemento semántico que describa esa agrupación.

No uses <div> cuando exista un elemento que sí describe lo que es:
• ¿Es un párrafo? → <p>
• ¿Es una lista? → <ul>/<ol>/<dl>
• ¿Es una sección temática? → <section>
• ¿Es una pieza de contenido autocontenida? → <article>
• ¿Es navegación? → <nav>
• ¿Es el contenido principal? → <main>
• ¿Es un encabezado de página o sección? → <header>
• ¿Es un pie? → <footer>
• ¿Es complementario? → <aside>
• ¿Es un botón? → <button> (no un <div> clicable)
• ¿Es un enlace? → <a>

Ejemplo clásico (y problemático):

<div onclick=guardar()>Guardar</div>

Eso visualmente puede parecer un botón, pero:
• no es accesible por teclado como un botón real,
• no tiene rol semántico correcto,
• y no hereda comportamientos estándar.

Lo correcto:

<button type=button onclick=guardar()>Guardar</button>

Un mini-checklist para tus artículos y páginas

Cuando estés escribiendo contenido textual, prueba este repaso rápido:
1. ¿Cada idea completa está en un <p> (o elemento equivalente)?
2. ¿Si hay un conjunto de items, está en una lista real?
3. ¿Si cito a alguien, uso <blockquote> o <q> según el caso?
4. ¿El código está marcado como código (<code>, <pre>, <kbd>)?
5. ¿Las tablas tienen caption y encabezados (th, scope)?
6. ¿Estoy usando <div> solo cuando no hay alternativa semántica?

Si quieres, el siguiente artículo encaja muy bien si lo enfocamos en elementos de texto de detalle que suelen aparecer en contenidos reales: <strong>, <em>, <mark>, <abbr>, <time>, enlaces bien escritos, y cómo evitar el haz clic aquí para que la navegación por enlaces tenga sentido.

Estructura del contenido en una página HTML

En los artículos anteriores vimos la estructura general de un documento HTML, qué papel tiene el elemento <head> y cómo el <body> representa el contenido con el que el usuario interactúa.

En este artículo vamos a profundizar en cómo se organiza ese contenido dentro del <body> para que sea comprensible, navegable y accesible: hablaremos de landmarks (regiones), de secciones y de encabezados. La idea es construir una página que no solo se vea bien, sino que esté estructurada de forma que un lector de pantalla, un teclado o cualquier tecnología de asistencia pueda recorrerla como si fuese un mapa.

Estructura dentro del body

Cuando una página crece (menú, buscador, contenido, barras laterales, pie, etc.), el usuario necesita referencias para no perderse.

Visualmente se resuelve con columnas, cajas, colores y tamaños de letra. Pero para accesibilidad lo importante es la semántica, es decir: qué es cada zona y qué función cumple.

Para eso HTML nos ofrece elementos para definir regiones (<header>, <nav>, <main>, <footer>, <aside>), elementos para definir secciones (<article>, <section>) y encabezados: <h1> … <h6> para expresar jerarquía y permitir navegación por títulos de los contenidos.

Cuando se usan bien estas piezas, muchos lectores de pantalla permiten saltar por regiones (landmarks) y por encabezados de forma inmediata. Además, las herramientas de ayuda a la navegación para personas con discapacidad cognitiva entienden mejor la estructura de los contenidos y pueden ofrecer una mejor asistencia a los usuarios con discapacidad.

Landmarks

Los landmarks (regiones) son zonas del documento lo bastante importantes como para que el usuario quiera ir directamente a ellas (por ejemplo: navegación, contenido principal, pie).

A nivel técnico, se exponen como roles/landmarks en el árbol de accesibilidad.

En HTML moderno, muchos landmarks se consiguen sin ARIA, solo usando elementos semánticos:
• <header> (a nivel de página) suele exponerse como banner.
• <nav> como navigation.
• <main> como main.
• <aside> como complementary (contenido complementario).
• <footer> (a nivel de página) como contentinfo.

Importante matiz: el contexto importa. Por ejemplo, un <header> dentro de un <article> deja de ser landmark banner y pasa a ser un contenedor genérico, precisamente para evitar ruido y duplicidades.

Ejemplo de una estructura típica con landmarks y secciones

El siguiente ejemplo presenta una plantilla mental de cómo dividir una página en regiones y cómo dar sentido a cada bloque.

<body>

<a class=skip-link href=#contenido>Saltar al contenido principal</a>

<header>
<h1>Programar a ciegas</h1>
<p>Accesibilidad, usabilidad y desarrollo.</p>
</header>

<nav aria-label=Navegación principal>
<a href=/>Inicio</a>
<a href=/articulos/>Artículos</a>
<a href=/contacto/>Contacto</a>
</nav>

<main id=contenido>
<article>
<header>
<h2>Estructura del contenido en HTML</h2>
<p>Publicado el 1/01/2026</p>
</header>

<section>
<h3>¿Qué son los landmarks?</h3>
<p>
Los landmarks son regiones que ayudan a moverse por la página sin leerla de forma lineal.
</p>
</section>

<section>
<h3>Encabezados y jerarquía</h3>
<p>
Los encabezados crean un mapa del contenido y permiten saltar por secciones.
</p>
</section>
</article>
</main>

<aside aria-label=Contenido relacionado>
<h2>Artículos relacionados</h2>
<ul>
<li><a href=/?p=1331>Introducción a HTML</a></li>
<li><a href=/?p=1332>El head de una página HTML</a></li>
<li><a href=/?p=1344>El body de una página HTML</a></li>
</ul>
</aside>

<footer>
<p>&copy; 2026 Tyflos Accessible Software</p>
<a href=/accesibilidad/>Declaración de accesibilidad</a>
</footer>

</body>

Este ejemplo presenta los siguientes elementos clave:

  • Hay un enlace de salto (Saltar al contenido principal).
  • Hay un solo <main>, con un id para que el salto sea real.
  • La navegación principal está en <nav> y está etiquetada con aria-label para que, si en el futuro hay más de una navegación, podamos diferenciarlas.
  • El contenido principal está dentro de un <article> y dividido en <section> con encabezados.

El enlace para Saltar al contenido

Cuando una web repite cabecera y navegación en todas las páginas, un usuario que navega con teclado o lector de pantalla se encuentra siempre el mismo bloque antes de llegar al contenido real. WCAG exige un mecanismo para saltar bloques repetidos (criterio 2.4.1).

Un enlace de salto es la solución más habitual y sencilla.

Es opcional si ese enlace está siempre visible o si solo se muestra al recibir foco (lo habitual en muchos sitios).

Secciones

La estructuración en secciones y sub secciones definen la ordenación cognitiva general de los contenidos en una página web. Se suelen recomendar las siguientes reglas:

  • Usar <article> cuando el bloque tenga sentido por sí solo (una entrada de blog, una noticia, un comentario, una tarjeta de producto completa).
  • Usar <section> cuando se esté dividiendo un contenido en partes temáticas, normalmente con su propio encabezado.
  • Ambos elementos crean secciones en el documento y definen el alcance de cosas como <header> y <footer> internos.
  • No usar <section> como sustituto de <div>. Si no hay una sección temática real (y normalmente un encabezado que la titule), probablemente ese bloque sea un <div>.

Encabezados

Para una persona con discapacidad para el acceso a los contenidos digitales, como una persona ciega, los encabezados no son texto grande, más bien son un mecanismo de navegación y orientación.

Los encabezados definen la estructura de dependencias entre contenidos.

Un encabezado marca el comienzo de una sección dentro de los contenidos de la página.

Se suelen aplicar las siguientes reglas:

  • Siempre debe haber, al menos, un H1 en la página. 
  • Dentro del contenido del encabezado sólo debe haber texto o una imagen.
  • Ese texto o imagen debe representar el contenido que presenta el encabezado.
  • Nunca se debe usar encabezados para estilo visual.
  • Nunca se debe saltar niveles sin necesidad (por ejemplo, pasar de <h1> a <h4> porque sí).

Buenas prácticas para no crear ruido

Cuando se empieza a usar landmarks y ARIA, es fácil excederse en su uso. Un abuso o el renombrado excesivo de las regiones generan ruido y dificultan entender la página.

Se recomienda seguir estas reglas:

  • Un solo <main> por página.
  • Si hay varios <nav>, Es necesario poner nombre con aria-label (por ejemplo: Navegación principal, Navegación secundaria, Navegación de pie).
  • Se debe evitar crear regiones sin una razón semántica.
  • Usar <aside> para contenido complementario real (relacionado, pero no parte del hilo principal).

Cómo comprobar si la estructura es accesible

Se pueden detectar muchos fallos con herramientas automáticas, pero lo más fiable es realizar una verificación manual utilizando un lector de pantallas.
El lector de pantallas tiene una función para mostrar la estructura de encabezados en la página. De esta forma se puede observar si respetan el orden de anidamiento y si cuentan cómo se organiza el contenido en la página.
El lector de pantallas, por defecto, avisa cuando se ha encontrado una región (landmark). Es necesario revisar si aparecen regiones para la Navegación, Contenido principal, Pie, etc., y si tienen nombres claros cuando hay varias del mismo tipo.