Usa el flujo de lectura de CSS para la navegación de enfoque secuencial lógica

Fecha de publicación: 1 de mayo de 2025

Las propiedades reading-flow y reading-order de CSS están disponibles a partir de Chrome 137. En esta publicación, se explican los motivos detrás del diseño de estas propiedades y algunos detalles breves para comenzar a usarlas.

Los métodos de diseño, como la cuadrícula y el flex, transformaron el desarrollo del frontend. Sin embargo, su flexibilidad puede causar un problema para algunos usuarios. Es muy fácil crear una situación en la que el orden visual no coincida con el orden de la fuente en el árbol del DOM. Como este orden de origen es el que sigue el navegador si navegas por el sitio con un teclado, algunos usuarios pueden encontrar saltos inesperados mientras navegan por una página.

Las propiedades reading-flow y reading-order se diseñaron y agregaron a la especificación de visualización de CSS para intentar resolver este problema de larga data.

reading-flow

La propiedad CSS reading-flow controla el orden en que los elementos de un diseño flexible, de cuadrícula o de bloque se exponen a las herramientas de accesibilidad y cómo se enfocan con métodos de navegación secuencial lineal.

Toma un valor de palabra clave, con un valor predeterminado de normal, que mantiene el comportamiento de ordenar elementos en orden DOM. Para usarlo dentro de un contenedor flex, establece su valor en flex-visual o flex-flow. Para usarlo dentro de un contenedor de cuadrícula, establece su valor en grid-rows, grid-columns o grid-order.

reading-order

La propiedad CSS reading-order te permite anular manualmente el orden de los elementos dentro de un contenedor de flujo de lectura. Para usar esta propiedad dentro de una cuadrícula, un contenedor flex o de bloque, establece el valor reading-flow del contenedor en source-order y establece el reading-order del elemento individual en un valor entero.

Ejemplo en Flexbox

Por ejemplo, puedes tener un contenedor de diseño flexible con tres elementos en orden de fila inverso y también deseas usar la propiedad de orden para volver a mezclar ese orden.

<div class="box">
 <a href="#">One</a>
 <a href="#">Two</a>
 <a href="#">Three</a>
</div>
.box {
  display: flex;
  flex-direction: row-reverse;
}

.box :nth-child(1) {
  order: 2;
}

Puedes intentar navegar por estos elementos con la tecla TAB para encontrar el siguiente elemento enfocable y TAB + MAYÚSCULAS para encontrar el elemento enfocable anterior. Esto sigue los elementos en orden de origen: Uno, Dos, Tres.

Desde la perspectiva del usuario final, esto no tiene sentido y puede ser muy confuso. Lo mismo sucede si usamos una herramienta de navegación espacial de accesibilidad para navegar por la página.

Para solucionar este problema, configura la propiedad reading-flow:

.box {
  reading-flow: flex-visual;
}

El orden de enfoque ahora es: Uno, Tres, Dos. Esto es lo mismo que el orden visual que obtendrías si leyeras en inglés de izquierda a derecha.

Si, en cambio, prefieres mantener el orden de enfoque como se diseñó originalmente, en orden inverso, puedes establecer lo siguiente:

.box {
  reading-flow: flex-flow;
}

El orden de enfoque ahora es el orden flexible inverso: dos, tres y uno. En ambos casos, se considera la propiedad order del CSS.

Ejemplo con diseño de cuadrícula

Para ver cómo funciona esto en una cuadrícula, imagina que estás creando un diseño con elementos colocados automáticamente en la cuadrícula de CSS con doce áreas enfocables.

<div class="wrapper">
 <a href="#">One</a>
 <a href="#">Two</a>
 <a href="#">Three</a>
 <a href="#">Four</a>
 <a href="#">Five</a>
 <a href="#">Six</a>
 <a href="#">Seven</a>
 <a href="#">Eight</a>
 <a href="#">Nine</a>
 <a href="#">Ten</a>
 <a href="#">Eleven</a>
 <a href="#">Twelve</a>
</div>

Quieres que el quinto elemento secundario ocupe el espacio más grande en la parte superior, seguido del segundo elemento secundario hacia la mitad de la cuadrícula. Todos los demás elementos secundarios se pueden colocar automáticamente dentro de la cuadrícula siguiendo una plantilla de columna.

.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
}
.wrapper a:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper a:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

Intenta navegar por estos elementos con la tecla TAB para encontrar el siguiente elemento enfocable y las teclas TAB + MAYÚSCULAS para encontrar el elemento enfocable anterior. Esto sigue los elementos en orden de origen: del uno al doce.

Para solucionar este problema, configura la propiedad reading-flow:

.wrapper {
  reading-flow: grid-rows;
}

El orden de enfoque ahora es: Cinco, Uno, Tres, Dos, Cuatro, Seis, Siete, Ocho, Nueve, Diez, Once y Doce. Sigue el orden visual, fila por fila.

Si deseas que el flujo de lectura siga el orden de las columnas, puedes usar el valor de la palabra clave grid-columns. El orden de enfoque se convierte en Cinco, Seis, Nueve, Siete, Diez, Uno, Dos, Once, Tres, Cuatro, Ocho, Doce.

.wrapper {
  reading-flow: grid-columns;
}

También puedes intentar usar grid-order. El orden de enfoque permanece de uno a doce. Esto se debe a que no se estableció ningún pedido de CSS en ningún artículo.

Un contenedor de bloques con reading-order

La propiedad reading-order te permite especificar cuándo se debe visitar un elemento en el flujo de lectura, anulando el orden establecido por la propiedad reading-flow. Solo se aplica a un contenedor de flujo de lectura válido, cuando la propiedad reading-flow no es normal.

.wrapper {
  display: block;
  reading-flow: source-order;
}

.top {
  reading-order: -1;
  inset-inline-start: 50px;
  inset-block-start: 50px;
}

El siguiente contenedor de bloques contiene cinco elementos. No hay reglas de diseño que reordenen los elementos de su orden de origen, pero hay un elemento fuera del flujo que se debe visitar primero.

<div class="wrapper">
  <a href="#">Item 1</a>
  <a href="#">Item 2</a>
  <a href="#">Item 3</a>
  <a href="#">Item 4</a>
  <a class="top" href="#">Item 5</a>
</div>

Si configuras el reading-order de este elemento en -1, el orden de enfoque lo visita primero antes de volver al orden de origen para el resto de los elementos del flujo de lectura.

Puedes encontrar más ejemplos en el sitio chrome.dev.

Interacción con tabindex

Históricamente, los desarrolladores han usado el atributo global tabindex de HTML para que los elementos HTML sean enfocables y determinar el orden relativo para la navegación de enfoque secuencial. Sin embargo, este atributo tiene muchas desventajas y problemas de accesibilidad. La principal preocupación es que el árbol de accesibilidad no reconoce la navegación de enfoque ordenada por el índice de tabulación que se crea con un índice de tabulación positivo. Si se usa de forma incorrecta, es posible que obtengas un orden de enfoque irregular que no coincida con la experiencia en un lector de pantalla. Para solucionarlo, haz un seguimiento del orden con el atributo HTML aria-owns.

En el ejemplo de flex anterior, para obtener el mismo resultado que con reading-flow: flex-visual, puedes hacer lo siguiente.

<div class="box" aria-owns="one three two">
  <a href="#" tabindex="1" id="one">One</a>
  <a href="#" tabindex="3" id="two">Two</a>
  <a href="#" tabindex="2" id="three">Three</a>
</div>

Pero, ¿qué sucede si otro elemento fuera del contenedor también tiene tabindex=1? Luego, se visitarán todos los elementos con tabindex=1 juntos, antes de pasar al siguiente valor incremental de tabindex. Esta navegación secuencial con saltos generará una mala experiencia del usuario. Por lo tanto, los expertos en accesibilidad recomiendan evitar un valor positivo de tabindex. Intentamos corregir esto cuando diseñamos reading-flow.

Un contenedor que tiene el conjunto de propiedades reading-flow se convierte en un propietario del alcance de enfoque. Esto significa que abarca la navegación de enfoque secuencial para visitar cada elemento dentro del contenedor antes de pasar al siguiente elemento enfocado en un documento web. Además, sus elementos secundarios directos se ordenan con la propiedad de flujo de lectura y se ignora el índice de tabulación positivo para el orden. Aún es posible establecer un tabindex positivo en los elementos secundarios de un elemento de flujo de lectura.

Ten en cuenta que un elemento con display: contents que hereda la propiedad reading-flow de su elemento superior de diseño también será un contenedor de flujo de lectura válido. Ten esto en cuenta cuando diseñes tu sitio. Obtén más información sobre esto en nuestra solicitud de comentarios sobre reading-flow y display: contents.

Envíanos tus comentarios

Prueba los ejemplos de esta publicación y los ejemplos de reading-flow en chrome.dev, y usa estas propiedades CSS en tus sitios. Si tienes comentarios, infórmalos como un problema en el repositorio de GitHub del grupo de trabajo de CSS. Si tienes comentarios específicos sobre el comportamiento del tabindex y el enfoque de alcance, infórmalo como un problema en el repositorio de GitHub de HTML WHATNOT. Nos encantaría recibir tus comentarios sobre esta función.