Flexbox
El primer modelo de layout moderno. Cómo distribuir espacio en una dimensión, alinear y centrar elementos de manera predecible. La herramienta principal para UI components
Esta nota cubre el capítulo 11 del libro: Flexbox, el primer modelo de layout moderno de CSS. Permite distribuir espacio en una dimensión, alinear elementos, centrar contenido y crear layouts flexibles. La herramienta principal para UI components como navbars, cards, listas y formularios.
Por qué flexbox
Antes de flexbox, los layouts se hacían con float, position, inline-block y muchos hacks. Flexbox resolvió el problema de distribuir espacio en una dimensión.
Problemas que flexbox resolvió:
- Centrar vertical y horizontalmente.
- Distribuir espacio entre items.
- Hacer que los items crezcan o se encojan.
- Alinear en el eje principal.
- Alinear en el eje secundario.
- Reordenar items.
Flexbox vs Grid:
Flexbox: layout en 1D (una fila O una columna).
Grid: layout en 2D (filas Y columnas).
Usa flexbox para:
- Navbars, sidebars, cards, listas.
- Cualquier cosa en una dimensión.
Usa grid para:
- Layouts de página, grids complejos.
- Cualquier cosa en 2D.
Conceptos básicos
.container {
display: flex;
}
Conceptos:
- Flex container: el padre con display: flex.
- Flex items: los hijos directos.
- Main axis: el eje principal (horizontal por default).
- Cross axis: el eje perpendicular.
- Main start / main end: inicio y fin del eje principal.
- Cross start / cross end: inicio y fin del eje cruzado.
flex-direction: row (default)
main start
┌───────┬───────┬───────┐
│ item1 │ item2 │ item3 │
└───────┴───────┴───────┘
main end
cross start
cross end
flex-direction
.container {
display: flex;
flex-direction: row; /* horizontal, default */
flex-direction: row-reverse; /* horizontal invertido */
flex-direction: column; /* vertical */
flex-direction: column-reverse; /* vertical invertido */
}
flex-direction:
- row: horizontal, start a end.
- row-reverse: horizontal, end a start.
- column: vertical, top a bottom.
- column-reverse: vertical, bottom a top.
flex-wrap
.container {
display: flex;
flex-wrap: nowrap; /* default, todo en una línea */
flex-wrap: wrap; /* varios items por línea */
flex-wrap: wrap-reverse; /* varios items en líneas invertidas */
}
flex-wrap:
- nowrap: default, sin saltos.
- wrap: items saltan a la siguiente línea.
- wrap-reverse: items saltan a la línea de arriba.
flex-flow shorthand
.container {
flex-flow: row wrap; /* flex-direction + flex-wrap */
flex-flow: column nowrap;
}
justify-content
Cómo distribuir los items en el eje principal:
.container {
display: flex;
justify-content: flex-start; /* default */
justify-content: flex-end;
justify-content: center;
justify-content: space-between; /* espacio entre items */
justify-content: space-around; /* espacio alrededor */
justify-content: space-evenly; /* espacio equitativo */
}
justify-content:
- flex-start: items al inicio.
- flex-end: items al final.
- center: items centrados.
- space-between: primer y último al borde, resto espaciado.
- space-around: espacio igual alrededor de cada item.
- space-evenly: espacio igual ENTRE items.
Visualización
flex-start: [item1][item2][item3]
flex-end: [item1][item2][item3]
center: [item1][item2][item3]
space-between: [item1] [item2] [item3]
space-around: [item1] [item2] [item3]
space-evenly: [item1] [item2] [item3]
align-items
Cómo alinear los items en el eje cruzado:
.container {
display: flex;
align-items: stretch; /* default, estira al alto */
align-items: flex-start; /* al inicio */
align-items: flex-end; /* al final */
align-items: center; /* centrado */
align-items: baseline; /* alineado por la base del texto */
}
align-items:
- stretch: estira al alto del contenedor.
- flex-start: al inicio del cross axis.
- flex-end: al final.
- center: centrado.
- baseline: alineado por la base del texto.
Visualización
stretch: los items se estiran al alto del contenedor
flex-start: alineados al top
flex-end: alineados al bottom
center: centrados verticalmente
baseline: alineados por la base del texto
align-content
Cuando hay varias líneas (flex-wrap: wrap), cómo se distribuyen:
.container {
display: flex;
flex-wrap: wrap;
align-content: stretch; /* default */
align-content: flex-start;
align-content: flex-end;
align-content: center;
align-content: space-between;
align-content: space-around;
align-content: space-evenly;
}
align-content:
- Similar a justify-content, pero en el cross axis.
- Solo aplica cuando hay múltiples líneas.
- Con una línea, no tiene efecto.
gap
.container {
display: flex;
gap: 1rem; /* ambos ejes */
gap: 1rem 2rem; /* row | column */
row-gap: 1rem;
column-gap: 2rem;
}
gap:
- Espacio entre items.
- row-gap: espacio entre filas.
- column-gap: espacio entre columnas.
- Funciona en flex, grid, multi-column.
- Alternativa moderna a márgenes.
El libro es claro: si quieres espacio entre items, usa gap. Los margin en flexbox hijos no se colapsan y crean espacios no deseados.
align-self
Sobreescribe align-items para un item específico:
.item-1 {
align-self: flex-end;
}
.item-2 {
align-self: center;
}
align-self:
- auto: usa el align-items del padre.
- flex-start, flex-end, center, baseline, stretch.
- Solo afecta a un item.
Order
Reordena los items sin tocar el HTML:
.item-1 { order: 3; }
.item-2 { order: 1; }
.item-3 { order: 2; }
/* Render: item2, item3, item1 */
order:
- Default: 0.
- Valor más bajo: aparece antes.
- Mismo valor: el orden del DOM.
- Útil para reordenar responsive.
- Cuidado: afecta el orden de tabulación y accesibilidad.
flex-grow
Cómo crece el item cuando sobra espacio:
.item-1 {
flex-grow: 1; /* ocupa el espacio sobrante */
}
.item-2 {
flex-grow: 2; /* ocupa el doble que .item-1 */
}
flex-grow:
- 0: no crece (default).
- 1: ocupa el espacio sobrante.
- 2: el doble que un item con flex-grow: 1.
- El espacio se distribuye proporcionalmente.
Ejemplo completo
.container {
display: flex;
}
.item-1 { flex-grow: 1; }
.item-2 { flex-grow: 1; }
.item-3 { flex-grow: 2; }
/* Si el container es 600px y los items tienen 100px cada uno:
Sobra: 600 - 300 = 300px.
Se distribuye: 100 a item-1, 100 a item-2, 200 a item-3.
Tamaño final: 200, 200, 300.
*/
flex-shrink
Cómo se encoge el item cuando no hay espacio:
.item {
flex-shrink: 1; /* default, se encoge */
flex-shrink: 0; /* no se encoge */
flex-shrink: 2; /* se encoge el doble */
}
flex-shrink:
- 1: se encoge proporcionalmente (default).
- 0: no se encoge (mantiene su tamaño).
- N: se encoge N veces más.
- Útil para evitar que un item se haga muy pequeño.
flex-basis
El tamaño inicial antes de distribuir el espacio:
.item {
flex-basis: 200px; /* tamaño inicial de 200px */
flex-basis: 50%; /* 50% del contenedor */
flex-basis: auto; /* el width del item (default) */
flex-basis: content; /* el contenido (default en column) */
}
flex-basis:
- El tamaño "base" del item.
- El espacio se distribuye después de flex-basis.
- auto: usa el width/height según flex-direction.
- content: el contenido del item.
flex shorthand
.item {
flex: 1; /* flex-grow: 1, flex-shrink: 1, flex-basis: 0 */
flex: auto; /* flex-grow: 1, flex-shrink: 1, flex-basis: auto */
flex: none; /* flex-grow: 0, flex-shrink: 0, flex-basis: auto */
flex: 1 1 200px; /* grow | shrink | basis */
flex: 1 0 auto; /* grow | shrink | basis */
}
flex:
- Un valor: flex-grow.
- Dos valores: flex-grow, flex-shrink.
- Tres valores: flex-grow, flex-shrink, flex-basis.
- auto: 1 1 auto.
- none: 0 0 auto.
- initial: 0 1 auto.
El libro señala: flex: 1 (también flex: 1 1 0) es el patrón más usado. El item crece y se encoge para llenar el espacio.
El famoso truco del centrado
.center {
display: flex;
justify-content: center;
align-items: center;
}
Centrado perfecto:
- justify-content: center: horizontal.
- align-items: center: vertical.
- El item se centra en ambos ejes.
- Funciona con cualquier tamaño de item.
- Funciona con cualquier tamaño de contenedor.
Navegación típica
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1em;
}
.nav-links {
display: flex;
gap: 1em;
list-style: none;
}
Card grid simple
.card-container {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.card {
flex: 1 1 300px; /* crece y se encoge, base 300px */
padding: 1em;
border: 1px solid #ccc;
border-radius: 8px;
}
Card grid:
- flex-wrap: wrap: múltiples líneas.
- flex: 1 1 300px: cada card ocupa al menos 300px.
- gap: espacio entre cards.
- Solución simple para un grid de cards.
Sticky footer
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1; /* ocupa el espacio sobrante */
}
footer {
/* tamaño natural */
}
Sticky footer:
- El body es un flex container.
- main crece para ocupar el espacio.
- El footer queda abajo.
- Sin flexbox, esto requería JavaScript.
Centrar con margin auto
.container {
display: flex;
}
.item {
margin: auto; /* centrado en ambos ejes */
}
margin auto en flex:
- En flex items, margin: auto se expande.
- Útil para empujar un item al final.
- margin-left: auto empuja a la derecha.
Casos de estudio
Navbar
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1em 2em;
background: #333;
color: white;
}
.navbar-brand {
font-size: 1.5em;
font-weight: bold;
}
.navbar-links {
display: flex;
gap: 1em;
list-style: none;
}
.navbar-link {
color: white;
text-decoration: none;
}
Card
.card {
display: flex;
flex-direction: column;
gap: 1em;
padding: 1em;
border: 1px solid #ccc;
border-radius: 8px;
}
.card-image {
width: 100%;
height: 200px;
object-fit: cover;
}
.card-body {
flex: 1; /* empuja el footer al final */
}
.card-footer {
display: flex;
justify-content: space-between;
}
Form
.form {
display: flex;
flex-direction: column;
gap: 1em;
max-width: 400px;
margin: 0 auto;
}
.form-group {
display: flex;
flex-direction: column;
gap: 0.25em;
}
.form-actions {
display: flex;
gap: 0.5em;
justify-content: flex-end;
}
min-width: 0 y flexbox
.flex-container {
display: flex;
}
.flex-item {
/* Por defecto, min-width: auto */
/* Los items no se encogen más allá de su contenido */
min-width: 0; /* permite que se encojan */
}
min-width: 0:
- El valor default es auto, no 0.
- Los items no se encogen más allá de su contenido natural.
- Para layouts flexibles, hay que poner min-width: 0.
Errores comunes
/* Mal: height: 100% en flex item */
.flex-item {
height: 100%; /* a veces no funciona */
}
/* Mejor: stretch (default) */
.flex-container {
align-items: stretch;
}
/* Mal: margin en items */
.flex-item {
margin: 1em; /* crea espacio INESPERADO */
}
/* Mejor: gap */
.flex-container {
gap: 1em;
}
/* Mal: text-align en flex */
.flex-container {
text-align: center; /* no funciona */
}
/* Mejor: justify-content */
.flex-container {
justify-content: center;
}
Resumen en tres frases
- Flexbox es un layout unidimensional: alinea y distribuye elementos en una fila o columna. La herramienta principal para UI components.
- Las propiedades clave son
flex-direction,justify-content(eje principal),align-items(eje cruzado),flex-wrap,gap,flex-grow,flex-shrinkyflex-basis. - El truco más útil es
display: flex; justify-content: center; align-items: center;para centrar perfectamente en ambos ejes.
Próximos pasos
- Grid Layout: el modelo de layout bidimensional. Permite crear grids complejos con filas y columnas, ideal para layouts de página completos.