Los valores: start, flex-start, self-start y toda la familia
El catálogo completo de valores de alineación clasificado por familia, con la diferencia real entre start y flex-start, cuándo importa self-start, y la aritmética de space-around frente a space-evenly.
El módulo de alineación admite una veintena de valores, y la mayoría de la gente usa cuatro. El problema no es que sobren dieciséis: es que entre los que no se usan están precisamente los que resuelven los casos difíciles —contenido bidireccional, líneas base entre columnas, desbordamiento sin pérdida de datos—. Clasificarlos por familia convierte una lista inmemorizable en cuatro grupos con una lógica cada uno.
- Clasificar cualquier valor de alineación en su familia y saber qué propiedades lo aceptan.
- Explicar la diferencia entre
start,flex-startyself-startcon un caso donde divergen. - Calcular el reparto de espacio de
space-between,space-aroundyspace-evenly. - Saber cuándo
stretchtiene efecto y cuándo lo pierde.
Familia 1: posicionales
Colocan el sujeto en un punto del contenedor. Los acepta cualquier propiedad del módulo.
center: el que todo el mundo conoce.startyend: relativos al modo de escritura del contenedor. Son los modernos y los que deberías escribir por defecto.flex-startyflex-end: relativos aflex-direction. Solo tienen sentido en Flexbox; en Grid y bloque se tratan comostartyend.self-startyself-end: relativos al modo de escritura del propio elemento. Solo en autoalineación.leftyright: físicos. En el eje de bloque se comportan comostart.
La divergencia entre start y flex-start es real y se ve con flex-direction: row-reverse:
.invertida {
display: flex;
flex-direction: row-reverse;
justify-content: flex-start; /* al inicio del EJE, o sea a la derecha */
}
.invertida-logica {
display: flex;
flex-direction: row-reverse;
justify-content: start; /* al inicio de la LINEA, o sea a la izquierda */
}
En un contenedor normal los dos coinciden y por eso nadie nota la diferencia. En cuanto inviertes la dirección o cambias a un idioma de derecha a izquierda, dejan de coincidir y hay que saber cuál querías.
self-start importa cuando un elemento tiene su propio direction o writing-mode distinto del contenedor: un bloque de texto en árabe dentro de una página en español. start lo alinearía según el contenedor; self-start lo alinea según el propio bloque, que casi siempre es lo que un lector espera.
Familia 2: líneas base
baseline, first baseline y last baseline alinean los sujetos por una línea de texto en vez de por un borde. Solo tienen sentido en autoalineación.
.formulario {
display: grid;
grid-template-columns: max-content 1fr;
gap: 0.5rem 1rem;
align-items: baseline; /* la etiqueta se alinea con el texto del campo */
}
Esto es lo que hace que una etiqueta y un campo con distinta altura o distinto tamaño de fuente queden ópticamente alineados, cosa que center no consigue nunca porque los cuerpos tipográficos no están centrados en su caja.
last baseline es el caso raro y útil: alinea por la última línea de texto, que es lo que quieres cuando las tarjetas tienen títulos de una o dos líneas y quieres que el pie coincida.
En Grid, la alineación por línea base agrupa los elementos que comparten fila o columna en un grupo de líneas base y los alinea entre sí; en Flexbox, los de la misma línea de flex.
Familia 3: distribución
Solo las aceptan justify-content y align-content, porque solo tienen sentido cuando hay varios sujetos entre los que repartir.
Con cinco elementos y un espacio sobrante S:
space-between: cero antes del primero y después del último;S/4en cada uno de los cuatro huecos internos.space-around: cada elemento recibeS/5de espacio, mitad a cada lado; los extremos quedan conS/10y los huecos internos conS/5. De ahí que los bordes parezcan la mitad de anchos.space-evenly: los seis espacios —cuatro internos y los dos extremos— midenS/6. Es el único que produce un reparto ópticamente uniforme.
.barra { display: flex; justify-content: space-between; } /* pegado a los bordes */
.pasos { display: flex; justify-content: space-evenly; } /* uniforme de verdad */
Un detalle importante: la especificación define qué pasa cuando el reparto no tiene sentido. Si el espacio sobrante es negativo —hay desbordamiento— o si solo hay un sujeto, space-between se comporta como start y tanto space-around como space-evenly se comportan como center. No producen resultados absurdos: degradan a un posicional.
Es el valor más usado por accidente y el que peor queda: los márgenes exteriores miden la mitad que los interiores, lo que crea una asimetría visual que nadie ha pedido. Si buscas un reparto uniforme, es space-evenly. Si buscas los extremos pegados a los bordes, es space-between. space-around solo tiene sentido cuando quieres exactamente esa proporción 1:2:2:1.
Familia 4: stretch y normal
stretch estira el sujeto para llenar su hueco, y solo hace algo si la dimensión correspondiente está en auto. Un elemento con block-size: 4rem ignora align-self: stretch porque ya tiene tamaño; no es un fallo, es la definición.
.iguales {
display: flex;
align-items: stretch; /* todas las columnas a la altura de la mas alta */
}
.iguales > .fija { block-size: 4rem; } /* esta no se estira: ya tiene altura */
normal es el valor inicial de casi todas estas propiedades y su comportamiento depende del contexto: en Grid y en bloque se comporta como stretch; en Flexbox, align-items: normal también estira, mientras que justify-content: normal se comporta como flex-start. Es el único valor del módulo que no significa lo mismo en todas partes, precisamente porque su trabajo es representar “lo que este layout haría si no dijeras nada”.
Hay un caso donde stretch se rinde en silencio: los elementos con proporción intrínseca, como las imágenes. Un img con align-self: stretch en un flex de fila sí se estira, y deforma la imagen si no le pones object-fit. Merece la pena recordarlo antes de poner stretch en un contenedor genérico.
Escribir start en lugar de flex-start, inline-size en lugar de width y margin-inline en lugar de margin-left parece pedantería mientras solo publiques en un idioma. La razón para hacerlo no es la internacionalización, o no solo: es que los valores lógicos expresan la intención y los físicos expresan la implementación. Cuando escribes left, has decidido un hecho geométrico; cuando escribes start, has decidido un hecho semántico —“donde empieza la lectura”— y le has dejado al motor la traducción a geometría. La diferencia se cobra sola: el día que alguien meta direction: rtl en una sección, que un componente se reutilice dentro de un contenedor con writing-mode distinto, o que un usuario active un modo de lectura, el CSS lógico sigue diciendo la verdad y el físico ya no. Y es una apuesta sin riesgo, porque el soporte lleva años completo y el coste de escribirlo es exactamente cero. Este es el tipo de decisión que distingue a un CSS que un equipo puede mantener diez años: no cuesta nada hoy y elimina una clase entera de bugs futuros.
- Monta un flex con
flex-direction: row-reversey comparajustify-content: startconflex-start. - Alinea un formulario de dos columnas con
align-items: baseliney concenter, y compara ópticamente. - Coloca cinco elementos y mide en el inspector los huecos que producen
space-between,space-aroundyspace-evenly. - Pon
align-items: stretchen un contenedor con una imagen dentro y observa la deformación; corrígela conobject-fit: cover. - Crea un bloque con
direction: rtldentro de un contenedorltry comparastartconself-start.