wandres.dev
DIMENSIONAR · Tamaños intrínsecos y extrínsecos

Propiedades lógicas: inline-size frente a width

Los ejes en línea y de bloque, cómo el modo de escritura los rota, por qué todo el CSS diseñado después de 2015 está definido en ejes lógicos y qué ganas al cambiar el vocabulario.

⏱ 18 min

width significa “horizontal” y esa es toda su definición. inline-size significa “a lo largo de la dirección en la que fluye el texto”, que en español es horizontal y en japonés vertical puede ser otra cosa. La diferencia parece una cuestión de internacionalización y no lo es: el CSS moderno —flex, grid, container queries, alineación— está definido en ejes lógicos, y usar el vocabulario físico te obliga a traducir mentalmente en cada propiedad.

🎯 Al terminar esta lección sabrás
  • Definir el eje en línea y el eje de bloque y saber cómo los rota writing-mode.
  • Traducir el vocabulario físico completo al lógico sin dudar.
  • Explicar por qué flex y grid nunca hablan de arriba, abajo, izquierda o derecha.
  • Decidir cuándo el valor físico sigue siendo el correcto.

Los dos ejes

El eje en línea es la dirección en la que se suceden los caracteres dentro de una línea. El eje de bloque es la dirección en la que se apilan las líneas y los bloques. En español, con writing-mode: horizontal-tb, el eje en línea es horizontal y el de bloque es vertical. En vertical-rl, típico de composición japonesa, el eje en línea pasa a ser vertical y el de bloque horizontal, de derecha a izquierda.

Cada eje tiene un principio y un final: start y end. En español, inline-start es la izquierda y inline-end la derecha; con direction: rtl se intercambian. block-start es arriba y block-end abajo, salvo que el modo de escritura diga otra cosa.

físico lógico
width inline-size
height block-size
min-width min-inline-size
max-height max-block-size
margin-top margin-block-start
margin-left margin-inline-start
padding-bottom padding-block-end
border-right border-inline-end
top inset-block-start
left inset-inline-start
text-align: left text-align: start
float: left float: inline-start

Y a las abreviaturas por eje, que son la ganancia diaria real:

/* Dos declaraciones donde antes hacían falta cuatro */
.caja {
  margin-inline: auto;          /* izquierda y derecha */
  padding-block: 2rem 1rem;     /* arriba 2rem, abajo 1rem */
  border-inline-start: 3px solid #cba6f7;
  inset-block: 0;               /* arriba y abajo a cero */
}

inset como abreviatura de los cuatro desplazamientos es especialmente rentable: inset: 0 sustituye a cuatro declaraciones y es la forma canónica de estirar un absoluto sobre su bloque contenedor.

💡
La regla del margen de flujo

margin-block-start es lo que quieres para el ritmo vertical de un documento. El selector de hermano universal más esta propiedad da el mejor espaciador de contenido que existe: .flujo > * + * { margin-block-start: 1.5rem; }. Funciona en cualquier modo de escritura y no necesita conocer los elementos.

Por qué el layout moderno es lógico por dentro

Aquí está la razón que convierte esto de detalle culto en herramienta cotidiana. Flexbox no habla de horizontal ni vertical: habla de eje principal y eje transversal, y los deriva del modo de escritura. flex-direction: row significa “a lo largo del eje en línea”, no “de izquierda a derecha”. justify-content: flex-start alinea al principio del eje principal, sea donde sea que esté ese principio.

Grid hace lo mismo. grid-template-columns reparte el eje en línea, grid-template-rows el de bloque. justify-items alinea en el eje en línea y align-items en el de bloque. En vertical-rl, las “columnas” de tu grid se apilan verticalmente y todo sigue funcionando sin tocar una línea.

La consecuencia es concreta y molesta si la ignoras: si mezclas propiedades físicas con layout lógico, tu código deja de ser coherente consigo mismo. Un elemento flex con margin-left: auto funciona en row, no funciona igual en column, y hace algo distinto en row-reverse. El mismo elemento con margin-inline-start: auto sigue la lógica del contenedor en los tres casos.

/* Frágil: solo funciona en una dirección concreta */
.barra { display: flex; }
.barra .empujado { margin-left: auto; }

/* Coherente: empuja hacia el final del eje en línea sea cual sea */
.barra { display: flex; }
.barra .empujado { margin-inline-start: auto; }

Las container queries llevan el argumento al extremo. container-type: inline-size no tiene equivalente físico: la especificación eligió el eje lógico porque la consulta se define sobre el eje en el que el contenedor tiene tamaño determinable, y ese eje depende del modo de escritura. Las unidades cqi y cqb son lógicas también. No hay una versión física de esto, así que no puedes evitar aprender el vocabulario.

Cuándo el valor físico es el correcto

Sería un error convertir esto en dogma. Hay casos en los que lo físico es lo que quieres decir.

Una sombra proyectada apunta hacia donde está la fuente de luz, y la luz no rota con el modo de escritura: box-shadow: 0 4px 12px se queda como está. Lo mismo con translate, rotate y las transformaciones en general, que operan en el espacio físico de la pantalla y no tienen versión lógica.

Un icono con una flecha que indica “siguiente” debe voltearse en rtl, y ahí lo correcto no es una propiedad lógica sino un scale(-1, 1) condicionado con :dir(rtl).

Y los gradientes: linear-gradient(to right, ...) es físico y no existe la variante lógica, aunque puedes usar ángulos y calcularlos.

/* La sombra es física y está bien que lo sea */
.tarjeta {
  padding-block: 1rem;
  padding-inline: 1.25rem;
  box-shadow: 0 2px 8px rgb(0 0 0 / 0.15);
}

/* La flecha sí se voltea con la dirección */
.icono-siguiente:dir(rtl) { scale: -1 1; }

El criterio es limpio: si la propiedad describe una relación con el flujo del contenido, usa la lógica. Si describe una relación con el espacio físico de la pantalla, usa la física.

Las propiedades lógicas no son internacionalización, son una corrección del modelo

Es tentador archivar las propiedades lógicas en la carpeta de “cosas que hacer si tu producto se traduce al árabe”, y ese encuadre es el que hace que la mayoría de la gente nunca las adopte. La realidad es que son una corrección de un error de modelado que CSS arrastraba desde el principio. width y height mezclan dos conceptos que deberían haber estado separados: la geometría de la pantalla y la topología del flujo. Casi todo lo que haces con width en realidad se refiere a lo segundo —cuánto espacio ocupa esto en la dirección en la que se lee— y solo lo expresabas en términos de lo primero porque no había otra forma. La prueba de que el problema era de modelado, y no de idiomas, es que la corrección aparece en sitios donde la internacionalización no pinta nada: en la asimetría entre el eje en línea y el de bloque a la hora de dimensionar, en que container-type: inline-size sea posible y la consulta de altura no lo sea sin contain: size, en que un elemento flex tenga un mínimo automático solo en el eje principal. Todos esos comportamientos son consecuencias de la topología del flujo, no de la geometría, y son incomprensibles mientras sigas pensando en horizontal y vertical. Adoptar el vocabulario lógico no te prepara para traducir al árabe: te alinea con el modelo que el motor usa por dentro, y a partir de ahí las reglas dejan de parecer arbitrarias porque por fin las estás leyendo en su idioma original.

⚔️ Traduce y comprueba
  1. Coge una hoja de estilos tuya y traduce todas las propiedades de caja al vocabulario lógico.
  2. Aplica writing-mode: vertical-rl al contenedor raíz y observa qué sigue funcionando y qué no.
  3. Reproduce el caso del margin-left: auto en un flex row-reverse y compáralo con margin-inline-start: auto.
  4. Identifica en tu código tres propiedades que deban seguir siendo físicas y justifica por qué.
  5. Escribe un espaciador de flujo con margin-block-start y comprueba que también espacia correctamente en modo vertical.