wandres.dev
FLEXBOX EN LA PRÁCTICA · Alineación, orden y patrones

Los dos ejes y el orden visual

El eje principal y el transversal, cómo flex-direction rota el sistema entero, por qué row no significa horizontal, y el problema de accesibilidad que arrastran reverse y order.

⏱ 17 min

Flexbox no tiene filas ni columnas: tiene un eje principal, a lo largo del cual se colocan los elementos, y un eje transversal perpendicular a él. Todas las propiedades de alineación están definidas respecto a esos dos ejes y no respecto a la pantalla, así que cambiar flex-direction no gira los elementos: gira el significado de todo tu CSS. Entender esa rotación de vocabulario es lo que evita el ciclo de probar justify-content y align-items a ver cuál funciona.

🎯 Al terminar esta lección sabrás
  • Identificar el eje principal y el transversal para cualquier flex-direction.
  • Explicar por qué row depende del modo de escritura y no de la pantalla.
  • Enunciar el problema de accesibilidad de reverse y de order.
  • Elegir entre reordenar con order y reordenar el marcado.

Principal y transversal

El eje principal es el que marca flex-direction. Los elementos se colocan uno tras otro a lo largo de él. Tiene un principio, main-start, y un final, main-end.

El eje transversal es perpendicular al principal. Es el eje en el que un elemento se estira, se centra o se alinea por su línea base dentro de su línea. También tiene cross-start y cross-end.

flex-direction eje principal eje transversal
row el eje en línea el eje de bloque
row-reverse el eje en línea, invertido el eje de bloque
column el eje de bloque el eje en línea
column-reverse el eje de bloque, invertido el eje en línea

La segunda columna es la que suele malinterpretarse. row no significa horizontal: significa “a lo largo del eje en línea”. En un documento con writing-mode: vertical-rl, un contenedor flex-direction: row coloca sus elementos de arriba abajo, porque ahí el eje en línea es vertical.

Y row-reverse no invierte el orden de arriba abajo ni de izquierda a derecha en abstracto: intercambia main-start con main-end. En un documento rtl, row ya coloca de derecha a izquierda, y row-reverse lo pone de izquierda a derecha.

📝
La regla que resuelve la duda

justify-* siempre actúa en el eje principal. align-* siempre actúa en el eje transversal. Esa correspondencia no cambia nunca en flexbox ni en grid, así que la pregunta no es cuál de las dos usar, sino en qué eje quieres actuar. Si respondes eso, la propiedad se elige sola.

Qué cambia al cambiar la dirección

Pasar de row a column no rota nada visualmente: reasigna el significado de cinco cosas a la vez, y por eso rompe layouts que parecían robustos.

flex-basis pasa a fijar una altura en lugar de una anchura. Un flex: 1 1 20rem que era una columna de 20rem se convierte en un bloque de 20rem de alto.

justify-content pasa a distribuir verticalmente y align-items horizontalmente. El justify-content: center que centraba horizontalmente ahora centra verticalmente.

El estiramiento por defecto cambia de eje. Con row, align-items: stretch iguala las alturas; con column, iguala las anchuras.

flex-wrap genera columnas en lugar de filas, y align-content las distribuye horizontalmente.

Y el tamaño mínimo automático pasa a aplicarse sobre min-block-size en lugar de sobre min-inline-size.

/* Barra horizontal */
.barra { display: flex; justify-content: space-between; align-items: center; }

/* La misma barra en vertical: hay que intercambiar las dos propiedades */
.barra-vertical {
  display: flex;
  flex-direction: column;
  align-items: center;          /* ahora centra en horizontal */
  justify-content: space-between; /* ahora distribuye en vertical */
}

Una consecuencia práctica que se agradece: si escribes las alineaciones pensando en ejes y no en pantalla, cambiar la dirección en una media query o container query no requiere reescribir las alineaciones. Si las escribes pensando en horizontal y vertical, sí.

El problema de reverse y de order

row-reverse, column-reverse y la propiedad order cambian el orden visual de los elementos sin tocar el orden del DOM. Y el orden del DOM sigue siendo el que determina el recorrido con el tabulador y el orden de lectura de un lector de pantalla.

El resultado es un desajuste real y grave: un usuario que navega con teclado ve el foco saltar de un sitio a otro sin patrón aparente, y un usuario de lector de pantalla oye el contenido en un orden distinto del que ve alguien mirando la pantalla. No es un problema teórico: es uno de los fallos de accesibilidad más reportados en interfaces modernas.

La especificación de flexbox es inusualmente explícita al respecto: dice que estas propiedades son para reordenamiento visual y que los autores no deben usarlas para corregir un orden incorrecto en el documento fuente. Si el orden lógico es el que produce order, el marcado está mal.

/* Uso legítimo: el orden lógico no cambia, solo la disposición
   en un layout distinto donde la barra lateral va después */
@media (min-width: 60rem) {
  .lateral { order: -1; }
}
<!-- Uso ilegítimo: el botón principal está antes en el DOM
     y se mueve visualmente al final -->
<div class="acciones">
  <button class="principal">Guardar</button>
  <button class="secundaria">Cancelar</button>
</div>

En el caso ilegítimo, el arreglo correcto es cambiar el HTML. Un usuario de teclado espera que el primer botón que recibe el foco sea el primero que ve.

⚠️
row-reverse para invertir botones es el caso más frecuente

El patrón de poner los botones en el HTML en un orden y darles la vuelta con flex-direction: row-reverse circula mucho porque resuelve un problema real —el botón principal a la derecha en escritorio— con una línea. Y es exactamente el caso que la especificación desaconseja. Si necesitas invertir, invierte el marcado y usa margin-inline-start: auto para la separación.

Cuándo reordenar visualmente sí es correcto

Hay un criterio que funciona: order y reverse son correctos cuando el orden lógico no existe o cuando cambia legítimamente con el espacio disponible.

Una galería de imágenes sin jerarquía entre ellas no tiene orden lógico, así que reordenar es inocuo. Un layout que en móvil pone la navegación arriba y en escritorio a la izquierda cambia la disposición, no la jerarquía, y el orden del DOM sigue siendo válido en ambos casos aunque uno de los dos requiera order.

Lo que nunca es correcto es usar order para compensar un marcado en el que el orden de lectura es distinto del orden de importancia. Ese es un problema de HTML disfrazado de problema de CSS.

/* Comprobación rápida: desactiva todo el CSS de la página.
   Si el orden resultante es incomprensible, tu marcado está mal
   y ningún order lo va a arreglar. */
La abstracción de ejes es lo que permitió que grid y flex compartieran vocabulario

La decisión de definir flexbox sobre ejes abstractos en lugar de sobre horizontal y vertical parecía en 2012 una concesión a la internacionalización, y resultó ser la decisión de arquitectura más rentable del layout moderno. Al no hablar de pantalla, flexbox pudo definir un juego de propiedades de alineación —justify-content, align-items, align-self, align-content— que no contenían ninguna suposición sobre el modelo de layout concreto. Y entonces ocurrió lo interesante: cuando llegó grid, no tuvo que inventar su propio vocabulario, reutilizó ese. Y cuando la alineación se sacó a su propia especificación, CSS Box Alignment 3, se pudo extender al layout de bloque, al multicolumna y al de tabla sin cambiar una sola palabra clave. Hoy align-content funciona en un contenedor de bloque corriente y significa exactamente lo mismo que en flex. Esto es lo que se consigue cuando un estándar acierta con el nivel de abstracción, y es un patrón que reconocerás en el resto del lenguaje: gap empezó en grid y se extendió a flex y a multicolumna; las funciones de color relativo se definieron una vez y valen para todos los espacios; las container queries reutilizan la sintaxis de las media queries. Si estás diseñando cualquier sistema con vocación de durar, la lección es esta: el coste de encontrar la abstracción correcta se paga una vez, y el coste de no encontrarla se paga en cada extensión futura, para siempre.