Skip to content

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: flex y 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-content alinea en el eje principal.
  • align-items alinea 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:

Flexbox interactivo

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):

Navbar, tarjetas y footer con Flexbox

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 */
}
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 contenidoEl layout define el tamaño (estructura rígida)
Componentes: navbars, botones, tarjetas individualesLayouts 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 ​

  1. Crea un header con el logo a la izquierda y un botón "Contacto" a la derecha, centrados verticalmente.
  2. Haz tres columnas de igual ancho con 2rem de separación.
  3. Crea una galería de tarjetas que muestre 1 por fila en móvil y 3 en escritorio, sin media queries.
  4. En una fila con tres ítems, haz que el del medio ocupe todo el espacio sobrante y los otros sólo su contenido.
  5. 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: flex en el padre; los hijos directos se convierten en ítems flex.
  • justify-content alinea en el eje principal; align-items, en el cruzado.
  • flex-direction: column intercambia los ejes.
  • flex-wrap: wrap + flex: 1 1 250px = layouts responsive sin media queries.
  • gap separa ítems; margin: auto empuja elementos.
  • min-width: 0 soluciona desbordes de ítems que no se encogen.
  • Flexbox para componentes en una dimensión; Grid para layouts en dos.

Siguiente: CSS Grid a fondo.

Academia Web — aprende, copia y construye.