align-content
Flexbox
Distribuye el espacio entre múltiples líneas de ítems en el eje cruzado de un contenedor flex. Solo tiene efecto cuando hay flex-wrap: wrap y más de una línea de ítems.
align-content controla cómo se distribuyen las líneas de ítems en el eje cruzado de un contenedor flex cuando hay múltiples líneas. Es la contraparte de justify-content pero para el eje cruzado, y opera a nivel de línea — no de ítem individual. Su funcionamiento es análogo al de justify-content en el eje principal, pero aplica sobre las filas o columnas enteras de un layout que wrappea.
El gotcha más importante de toda la familia Flexbox: align-content no hace absolutamente nada a menos que se cumplan dos condiciones simultáneamente: (1) el contenedor tiene flex-wrap: wrap activo, y (2) los ítems efectivamente se distribuyen en más de una línea. Si todas las condiciones no se cumplen, la propiedad está declarada pero sin efecto visible, lo que confunde a quienes esperan que funcione como align-items.
La diferencia con align-items es crucial y merece entenderse bien: align-items alinea los ítems dentro de su propia línea (en el eje cruzado de cada línea); align-content distribuye el espacio entre las líneas mismas (en el eje cruzado del contenedor). En un contenedor de una sola línea, align-items tiene pleno efecto y align-content ninguno. En un contenedor con múltiples líneas, ambas pueden actuar simultáneamente: align-content decide cómo se distribuyen las líneas, y align-items decide cómo se alinean los ítems dentro de cada línea.
Cómo funciona
Con flex-wrap: wrap activo y más ítems de los que caben en una línea, el contenedor genera múltiples líneas en el eje cruzado. Si el contenedor tiene más espacio disponible en ese eje cruzado que el que ocupan todas las líneas juntas, align-content determina cómo se distribuye ese espacio sobrante. Los valores son los mismos que los de justify-content y tienen el mismo comportamiento lógico, pero en el eje perpendicular.
Para que haya espacio sobrante entre líneas, el contenedor necesita una dimensión explícita en el eje cruzado mayor que la suma de las alturas de todas las líneas. Con flex-direction: row, eso significa que el contenedor necesita un height definido y mayor que el total de filas.
Sintaxis
.contenedor {
display: flex;
flex-wrap: wrap; /* OBLIGATORIO — sin esto, align-content no hace nada */
align-content: stretch; /* valor por defecto */
align-content: flex-start;
align-content: flex-end;
align-content: center;
align-content: space-between;
align-content: space-around;
align-content: space-evenly;
}
Valores
stretch (valor por defecto)
Las líneas se estiran para ocupar todo el espacio disponible en el eje cruzado. El espacio libre se distribuye equitativamente entre todas las líneas, haciendo que cada una sea más alta (o ancha) de lo que sería su tamaño natural.
flex-start
Las líneas se agrupan al inicio del eje cruzado (cross-start). Con row, todas las filas quedan en la parte superior del contenedor; el espacio sobrante queda al final.
flex-end
Las líneas se agrupan al final del eje cruzado (cross-end). Con row, todas las filas quedan en la parte inferior del contenedor.
center
Las líneas se agrupan en el centro del eje cruzado. El espacio sobrante se divide entre el inicio y el final.
space-between
El espacio sobrante se distribuye entre las líneas. La primera línea queda pegada al inicio (cross-start) y la última al final (cross-end). No hay espacio en los extremos.
Cuándo usarlo: galerías donde se quiere que las filas de tarjetas ocupen el espacio vertical máximo con espacio igual entre filas.
space-around
Cada línea recibe la misma cantidad de espacio a ambos lados. El espacio entre dos líneas consecutivas es el doble del espacio en los extremos.
space-evenly
El espacio sobrante se distribuye de forma que haya exactamente la misma cantidad de espacio entre todas las líneas, incluyendo los extremos.
Ejemplo realista
.galeria {
display: flex;
flex-wrap: wrap; /* PASO 1: habilitar wrapping */
align-content: space-between; /* PASO 2: distribuir las filas */
gap: 16px;
height: 400px; /* necesita altura para tener espacio entre líneas */
}
.tarjeta {
width: 200px;
height: 100px;
}
Cuándo usar cada valor
| Situación | Valor |
|---|---|
| Filas de tarjetas con todo el espacio distribuido equitativamente | stretch |
| Filas agrupadas al inicio del contenedor | flex-start |
| Filas agrupadas al final (pie de contenedor) | flex-end |
| Filas centradas verticalmente en el contenedor | center |
| Filas en los extremos con espacio entre ellas | space-between |
| Espacio alrededor de cada fila (bordes con la mitad) | space-around |
| Espacio perfectamente uniforme entre todas las filas y los bordes | space-evenly |
Notas, gotchas e interacción
- ⚠️ Gotcha central: sin
flex-wrap: wrapy más de una línea, esta propiedad no hace nada. Es el error más frecuente: declararalign-contentesperando un efecto y no verlo porque los ítems no wrappean. Siempre verificar que haya múltiples líneas reales. align-itemsyalign-contentcoexisten pero operan a nivel diferente.align-contentdistribuye las líneas entre sí;align-itemsalinea los ítems dentro de cada línea. Si solo hay una línea,align-contentno hace nada peroalign-itemssí.- Necesita espacio libre en el eje cruzado para tener efecto. Si el contenedor no tiene
heightdeclarado (conrow), su altura se ajusta al contenido y no hay espacio extra entre líneas —align-contentno cambia nada visible. stretchcambia el tamaño de las líneas, no de los ítems. Constretch, las líneas crecen para llenar el espacio, pero los ítems dentro de cada línea crecen solo si no tienenheight/widthdeclarado (ahí entraalign-items: stretch).- Interacción con
gap.gapdefine un espacio mínimo entre ítems y entre líneas.align-contentdistribuye el espacio adicional por encima delgap. Si el contenedor es exactamente del tamaño que ocupan todas las líneas más losgap, no hay espacio extra paraalign-content.
Vigente / legacy
align-content es parte del módulo Flexbox Level 1, ampliamente soportado. No hay alternativa legacy para distribuir líneas en un layout multi-fila — antes de Flexbox, esto requería JavaScript o hacks con display: table. No se necesitan prefijos de vendor en proyectos modernos.