Tema
Flexbox a fondo
Flexbox revolucionó el maquetado web: alinear, centrar y repartir espacio, que antes requería trucos, ahora se hace con un par de líneas. Es la herramienta que más usarás en el día a día: barras de navegación, botones con íconos, tarjetas, formularios, footers. En esta lección lo dominarás por completo.
Concepto
Flexbox organiza elementos en una dimensión: en una fila o en una columna. Tiene dos protagonistas:
- Contenedor flex (el padre): recibe
display: flexy controla cómo se distribuyen sus hijos. - Ítems flex (los hijos directos): pueden crecer, encogerse y alinearse individualmente.
Analogía
Imagina una repisa (el contenedor) con libros (los ítems). Puedes decidir si los libros se juntan a la izquierda, al centro o se reparten a lo largo; si se alinean por arriba o por abajo; y si cuando no caben pasan a una segunda repisa.
Los dos ejes
txt
flex-direction: row (por defecto)
eje principal (main axis) ─────────────────────────▶
┌──────────────────────────────────────────────────┐ │
│ ┌─────┐ ┌─────┐ ┌─────┐ │ │ eje cruzado
│ │ 1 │ │ 2 │ │ 3 │ │ │ (cross axis)
│ └─────┘ └─────┘ └─────┘ │ │
└──────────────────────────────────────────────────┘ ▼justify-contentalinea en el eje principal.align-itemsalinea en el eje cruzado.- Si cambias a
flex-direction: column, los ejes se intercambian: el principal pasa a ser vertical.
Activar Flexbox
html
<div class="contenedor">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>css
.contenedor {
display: flex; /* los hijos se colocan en fila */
}Al instante, los ítems: se colocan en fila, toman el ancho de su contenido, se estiran a la altura del más alto y no se envuelven.
Experimenta con todas las propiedades del contenedor:
Propiedades del contenedor
flex-direction
css
.contenedor {
flex-direction: row; /* → por defecto */
flex-direction: row-reverse; /* ← */
flex-direction: column; /* ↓ */
flex-direction: column-reverse; /* ↑ */
}justify-content (eje principal)
css
.contenedor {
justify-content: flex-start; /* al inicio (por defecto) */
justify-content: center; /* al centro */
justify-content: flex-end; /* al final */
justify-content: space-between; /* primero y último en los extremos, el resto repartido */
justify-content: space-around; /* espacio alrededor de cada ítem (mitad en los bordes) */
justify-content: space-evenly; /* espacios exactamente iguales */
}txt
flex-start [1][2][3]
center [1][2][3]
flex-end [1][2][3]
space-between [1] [2] [3]
space-evenly [1] [2] [3]align-items (eje cruzado)
css
.contenedor {
align-items: stretch; /* se estiran para llenar la altura (por defecto) */
align-items: flex-start; /* arriba */
align-items: center; /* centrados verticalmente */
align-items: flex-end; /* abajo */
align-items: baseline; /* alineados por la línea base del texto */
}baseline es perfecto cuando los ítems tienen textos de distintos tamaños (un precio grande junto a "/mes").
flex-wrap
Por defecto (nowrap) los ítems se comprimen para caber en una línea. Con wrap pasan a la siguiente línea:
css
.contenedor {
flex-wrap: wrap;
}
/* Atajo: dirección + wrap */
.contenedor {
flex-flow: row wrap;
}gap
Espacio entre ítems (no en los bordes). Olvídate de márgenes con :last-child:
css
.contenedor {
gap: 1rem; /* filas y columnas */
gap: 2rem 1rem; /* filas | columnas */
row-gap: 2rem;
column-gap: 1rem;
}align-content
Sólo tiene efecto con varias líneas (flex-wrap: wrap) y espacio sobrante en el eje cruzado. Distribuye las líneas entre sí (acepta los mismos valores que justify-content más stretch).
Propiedades de los ítems
flex-grow: cuánto crece
Reparte el espacio sobrante proporcionalmente. Por defecto es 0 (no crece).
css
.item { flex-grow: 1; } /* todos crecen por igual */
.item.principal { flex-grow: 2; } /* este recibe el doble del espacio sobrante */flex-shrink: cuánto se encoge
Cuando falta espacio. Por defecto es 1 (todos se encogen). Con 0 el ítem no se encoge:
css
.logo { flex-shrink: 0; } /* el logo nunca se aplasta */flex-basis: tamaño inicial
El tamaño "ideal" antes de repartir el espacio (en el eje principal). Por defecto auto (usa width o el contenido).
css
.item { flex-basis: 250px; }El atajo flex (el que usarás siempre)
css
.item { flex: 1; } /* = 1 1 0% → crecen igual, ignorando el contenido: columnas iguales */
.item { flex: auto; } /* = 1 1 auto → crecen, pero partiendo del tamaño de su contenido */
.item { flex: none; } /* = 0 0 auto → tamaño fijo, ni crece ni se encoge */
.item { flex: 1 1 250px; } /* parte de 250px, crece y se encoge: ¡responsive sin media queries! */Buena práctica
Usa el atajo flex en lugar de las tres propiedades por separado. flex: 1 1 250px combinado con flex-wrap: wrap crea tarjetas que se acomodan solas: en móvil una por fila, en escritorio varias.
align-self
Sobrescribe align-items para un ítem concreto:
css
.item.especial { align-self: flex-end; }order
Cambia el orden visual (por defecto 0; menor va primero):
css
.imagen { order: -1; } /* pasa al principio */Accesibilidad
order sólo cambia el orden visual, no el del HTML. Quien navega con teclado o lector de pantalla sigue el orden del código. Úsalo con moderación (por ejemplo, reordenar una imagen en móvil), nunca para contenido cuyo orden importe.
margin: auto en flex
Un margen auto absorbe todo el espacio libre en esa dirección. Es un truco muy útil:
css
.nav__cta { margin-left: auto; } /* empuja este elemento (y los siguientes) a la derecha */Patrones reales
Así se ven varios de estos patrones juntos (redimensiona con los botones de dispositivo):
1. Centrado perfecto
css
.centrar {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}2. Navbar: logo a la izquierda, menú a la derecha
html
<nav class="nav">
<a href="/" class="nav__logo">Estudio Nova</a>
<ul class="nav__menu">
<li><a href="#servicios">Servicios</a></li>
<li><a href="#proyectos">Proyectos</a></li>
<li><a href="#contacto">Contacto</a></li>
</ul>
</nav>css
.nav {
display: flex;
justify-content: space-between; /* logo a un lado, menú al otro */
align-items: center; /* centrados verticalmente */
gap: 1rem;
padding: 1rem 1.5rem;
}
.nav__menu {
display: flex; /* el ul también es flex: enlaces en fila */
gap: 1.5rem;
list-style: none;
margin: 0;
padding: 0;
}3. Tarjetas con botón alineado abajo
Problema clásico: tarjetas con textos de distinto largo y los botones desalineados.
css
.tarjetas {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.tarjeta {
flex: 1 1 260px; /* mínimo ~260px, crecen para llenar la fila */
display: flex;
flex-direction: column; /* contenido en columna */
}
.tarjeta__boton {
margin-top: auto; /* empuja el botón al fondo de la tarjeta */
}4. Footer pegado abajo (sticky footer)
css
body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
main {
flex: 1; /* el main ocupa todo el espacio sobrante */
}5. Media object (imagen + texto)
html
<div class="testimonio">
<img src="img/ana.webp" alt="" class="testimonio__foto">
<div>
<p>"Excelente servicio, mi sitio quedó increíble."</p>
<strong>Ana López</strong>
</div>
</div>css
.testimonio {
display: flex;
align-items: flex-start;
gap: 1rem;
}
.testimonio__foto {
flex-shrink: 0; /* la foto no se aplasta */
width: 56px;
height: 56px;
border-radius: 50%;
}6. Input con botón
css
.buscador {
display: flex;
}
.buscador input {
flex: 1; /* el input toma todo el espacio */
min-width: 0; /* evita desbordes en pantallas pequeñas */
}
.buscador button {
flex: none;
}Error común: el ítem no se encoge
Los ítems flex tienen min-width: auto, así que nunca se encogen por debajo del ancho de su contenido (una URL larga, un input). Si algo se desborda dentro de un contenedor flex, añade min-width: 0 al ítem.
7. Menú responsive: columna en móvil, fila en escritorio
css
.menu {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
@media (min-width: 768px) {
.menu {
flex-direction: row;
gap: 2rem;
}
}Flexbox o Grid
| Usa Flexbox cuando... | Usa Grid cuando... |
|---|---|
| Organizas en una dimensión (fila o columna) | Necesitas filas y columnas a la vez |
| El tamaño depende del contenido | El layout define el tamaño (estructura rígida) |
| Componentes: navbars, botones, tarjetas individuales | Layouts de página, galerías, dashboards |
En la práctica se combinan: Grid para la estructura de la página y Flexbox dentro de cada componente.
Ejercicios
- Crea un header con el logo a la izquierda y un botón "Contacto" a la derecha, centrados verticalmente.
- Haz tres columnas de igual ancho con 2rem de separación.
- Crea una galería de tarjetas que muestre 1 por fila en móvil y 3 en escritorio, sin media queries.
- En una fila con tres ítems, haz que el del medio ocupe todo el espacio sobrante y los otros sólo su contenido.
- Crea un botón con un ícono y texto, perfectamente alineados y con 8px de separación.
Ver solución
css
/* 1 */
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
/* 2 */
.columnas {
display: flex;
gap: 2rem;
}
.columnas > * {
flex: 1;
}
/* 3: cada tarjeta mide como mínimo 280px; si caben 3, se ponen 3 */
.galeria {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.galeria .tarjeta {
flex: 1 1 280px;
}
/* 4 */
.fila {
display: flex;
}
.fila .medio {
flex: 1;
}
/* 5 */
.boton-icono {
display: inline-flex; /* flex, pero el botón sigue en línea */
align-items: center;
gap: 8px;
}Resumen
display: flexen el padre; los hijos directos se convierten en ítems flex.justify-contentalinea en el eje principal;align-items, en el cruzado.flex-direction: columnintercambia los ejes.flex-wrap: wrap+flex: 1 1 250px= layouts responsive sin media queries.gapsepara ítems;margin: autoempuja elementos.min-width: 0soluciona desbordes de ítems que no se encogen.- Flexbox para componentes en una dimensión; Grid para layouts en dos.
Siguiente: CSS Grid a fondo.