Flexbox llegó a todos los principales navegadores alrededor de 2015 y resolvió de inmediato el problema que los desarrolladores habían estado esquivando durante una década: el centrado vertical. Pero la mayoría lo aprendió al revés — memorizaron justify-content: center de una hoja de referencia sin entender por qué funciona. Cuando el diseño no se comporta bien, esa brecha en la comprensión convierte una tarea de cinco minutos en una hora de prueba y error. Esta guía construye primero el modelo mental y luego cubre cada propiedad que realmente importa en proyectos reales.
El modelo mental: un eje a la vez
El concepto central de Flexbox es que distribuye los elementos a lo largo de un único eje. Hay un eje principal — la dirección en la que fluyen los elementos — y un eje transversal, que corre perpendicular. El punto crítico que casi todos los principiantes pierden: flex-direction determina cuál eje es cuál. Todo lo demás deriva de eso.
/* Default: main axis runs LEFT → RIGHT, cross axis runs TOP → BOTTOM */
.container {
display: flex;
flex-direction: row; /* default */
}
/* Rotated: main axis now runs TOP → BOTTOM, cross axis runs LEFT → RIGHT */
.container {
display: flex;
flex-direction: column;
}
/*
justify-content → controls alignment on the MAIN axis
align-items → controls alignment on the CROSS axis
This is why centering something in both axes looks like this:
*/
.center-both {
display: flex;
justify-content: center; /* horizontally centred (main axis = row) */
align-items: center; /* vertically centred (cross axis) */
}flex-direction: column, justify-content ya no controla la alineación horizontal — controla la alineación vertical, porque el eje principal ha girado. align-items ahora controla lo horizontal. Ten en mente esta rotación siempre que algo no se alinee donde lo esperas.Propiedades del contenedor
Estas propiedades van en el contenedor flex — el elemento padre con display: flex. Controlan cómo se distribuyen y alinean todos los elementos hijo.
/* display: flex makes the element a block-level flex container.
display: inline-flex makes it inline (sits in text flow). */
.nav {
display: flex;
}
/* flex-direction — which way does the main axis run? */
.nav {
flex-direction: row; /* left to right (default) */
flex-direction: row-reverse; /* right to left */
flex-direction: column; /* top to bottom */
flex-direction: column-reverse; /* bottom to top */
}
/* flex-wrap — what happens when items overflow the container? */
.card-grid {
flex-wrap: nowrap; /* all items forced onto one line (default) */
flex-wrap: wrap; /* items wrap onto additional lines */
flex-wrap: wrap-reverse; /* items wrap in reverse order */
}
/* gap — space between items. Modern approach; avoids margin hacks. */
.card-grid {
gap: 1.5rem; /* same in both directions */
gap: 1rem 2rem; /* row-gap column-gap */
}La propiedad gap merece una mención especial. Antes de que existiera, el patrón común era añadir márgenes a los elementos flex y luego cancelar los bordes exteriores con márgenes negativos. gap reemplaza todo eso limpiamente — úsalo en todas partes en su lugar.
/* justify-content — alignment on the MAIN axis */
.nav {
justify-content: flex-start; /* packed to start (default) */
justify-content: flex-end; /* packed to end */
justify-content: center; /* packed to centre */
justify-content: space-between; /* first/last at edges, equal gaps between */
justify-content: space-around; /* equal space around each item */
justify-content: space-evenly; /* equal space between every gap */
}
/* align-items — alignment on the CROSS axis (single line) */
.nav {
align-items: stretch; /* items fill cross-axis height (default) */
align-items: flex-start;/* items align to start of cross axis */
align-items: flex-end; /* items align to end of cross axis */
align-items: center; /* items centred on cross axis */
align-items: baseline; /* items aligned by their text baseline */
}
/* align-content — cross-axis alignment when there are MULTIPLE lines
(only takes effect with flex-wrap: wrap and enough items to wrap) */
.card-grid {
flex-wrap: wrap;
align-content: flex-start; /* rows packed to top */
align-content: center; /* rows centred vertically */
align-content: space-between; /* rows spread out with space between */
}Aquí hay una barra de navegación real que combina todo esto. El logo está a la izquierda, y los enlaces de navegación se empujan a la derecha usando margin-left: auto — un truco clásico de Flexbox. El enfoque justify-content: space-between también funciona, pero la técnica del margen automático es más flexible cuando tienes más de dos grupos.
/* Nav: logo left, links right */
.site-nav {
display: flex;
align-items: center;
gap: 1rem;
padding: 0 2rem;
height: 64px;
background: #1a1a2e;
}
.site-nav .logo {
font-size: 1.25rem;
font-weight: 700;
color: #fff;
text-decoration: none;
}
.site-nav .nav-links {
display: flex;
align-items: center;
gap: 1.5rem;
margin-left: auto; /* pushes everything after it to the right */
list-style: none;
margin-top: 0;
margin-bottom: 0;
padding: 0;
}
.site-nav .nav-links a {
color: #ccc;
text-decoration: none;
font-size: 0.9rem;
}
.site-nav .nav-links a:hover {
color: #fff;
}Propiedades de los elementos
Estas propiedades van en los elementos flex — los hijos directos del contenedor flex. Controlan cómo los elementos individuales crecen, se encogen y se dimensionan.
flex-grow— cuánto del espacio libre disponible reclama este elemento. Por defecto0(no crecer). Establecido en1en un elemento, toma todo el espacio restante.flex-shrink— cuánto se encoge este elemento en relación con los demás cuando no hay suficiente espacio. Por defecto1. Establecido en0para evitar que un elemento se encoja.flex-basis— el tamaño inicial del elemento antes de cualquier crecimiento o encogimiento. Puede ser una longitud (250px,30%) oauto(usar el tamaño del contenido del elemento).align-self— anulaalign-itemspara un elemento específico. Acepta los mismos valores:auto,flex-start,flex-end,center,baseline,stretch.order— cambia el orden visual sin tocar el HTML. Por defecto0. Los valores más bajos aparecen primero. Úsalo con moderación — rompe el orden de tabulación y causa problemas de accesibilidad para usuarios de teclado y lectores de pantalla.
/* Classic sidebar + main content layout */
.app-layout {
display: flex;
min-height: 100vh;
}
.sidebar {
flex: 0 0 280px; /* don't grow, don't shrink, always 280px wide */
background: #f5f5f5;
padding: 2rem 1.5rem;
}
.main-content {
flex: 1; /* grow to fill all remaining space */
padding: 2rem;
min-width: 0; /* critical: prevents content overflow in flex children */
}
/* Responsive: stack vertically on mobile */
@media (max-width: 768px) {
.app-layout {
flex-direction: column;
}
.sidebar {
flex: none; /* reset — don't use flex-basis on column layout */
}
}min-width: 0: por defecto, los elementos flex no pueden encogerse por debajo de su tamaño mínimo de contenido. Si tienes una palabra larga o una tabla ancha dentro de un elemento flex, desbordará en lugar de ajustarse. Añadir min-width: 0 al elemento flex lo soluciona. Aparece constantemente con el área de contenido principal en los diseños de barra lateral.La propiedad abreviada flex explicada
La propiedad abreviada flex empaqueta flex-grow, flex-shrink y flex-basis en una sola declaración. La especificación W3C define un puñado de valores de palabras clave que cubren los casos comunes, y con frecuencia se confunden entre sí.
/* flex: 1
Expands to: flex-grow: 1; flex-shrink: 1; flex-basis: 0%
Meaning: grow and shrink freely; start from zero (ignore content size).
All items with flex: 1 share space equally, regardless of content.
Most common choice for "fill available space". */
.tab { flex: 1; }
/* flex: auto
Expands to: flex-grow: 1; flex-shrink: 1; flex-basis: auto
Meaning: grow and shrink freely; start from the item's content size.
Items with more content get more space — proportional, not equal. */
.column { flex: auto; }
/* flex: none
Expands to: flex-grow: 0; flex-shrink: 0; flex-basis: auto
Meaning: completely rigid — don't grow, don't shrink, stay at content size.
Use for items that should never flex (icons, avatars, fixed labels). */
.avatar { flex: none; }
/* flex: 0 0 200px
Explicit: don't grow, don't shrink, always exactly 200px.
Same as writing out all three values. More readable for fixed-size items. */
.sidebar { flex: 0 0 200px; }
/* Practical difference: flex: 1 vs flex: auto in a tab bar
With flex: 1 → all tabs are equal width regardless of label length
With flex: auto → "Settings" tab is wider than "Home" tab */
.tabs { display: flex; }
.tab-equal { flex: 1; } /* equal width tabs */
.tab-auto { flex: auto; } /* content-sized tabs */Diseños reales comunes
Aquí hay cuatro patrones que usarás regularmente — construidos solo con Flexbox.
/* 1. Sticky footer
The footer always sits at the bottom, even on short pages.
body (or .app-shell) becomes a column flex container. */
body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
main {
flex: 1; /* expands to push footer down */
}
footer {
/* stays at the bottom */
}/* 2. Centred modal / hero content
Both axes centred — the Flexbox vertical-centring party trick. */
.hero {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 2rem;
background: linear-gradient(135deg, #667eea, #764ba2);
}
.hero-content {
max-width: 640px;
text-align: center;
color: #fff;
}/* 3. Nav bar: logo left, links right */
.site-nav {
display: flex;
align-items: center;
padding: 0 2rem;
height: 64px;
}
.site-nav .nav-links {
margin-left: auto; /* auto margin consumes all free space to its left */
display: flex;
gap: 1.5rem;
list-style: none;
padding: 0;
margin-top: 0;
margin-bottom: 0;
}/* 4. Card row that wraps on mobile */
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.card {
flex: 1 1 280px; /* grow and shrink, but never below 280px wide */
background: #fff;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
/* On wide screens: 3-4 cards per row.
On narrow screens: cards wrap into their own rows automatically.
No media query needed for the wrap itself — flex-wrap handles it. */Flexbox vs Grid — cuándo usar cada uno
Esta pregunta surge constantemente, y la respuesta es más simple de lo que la mayoría de los artículos hacen parecer: Flexbox es para diseños unidimensionales. CSS Grid es para diseños bidimensionales. Si estás distribuyendo elementos en una sola fila o una sola columna — una barra de navegación, un grupo de botones, una fila de tarjetas — Flexbox es la herramienta correcta. Si necesitas controlar filas y columnas simultáneamente — un diseño de página completa, un mosaico de fotos, una cuadrícula de formulario — usa Grid en su lugar.
En la práctica, usarás ambos en el mismo proyecto. Grid maneja la estructura a nivel de página (encabezado, barra lateral, contenido principal, pie de página). Flexbox maneja los componentes dentro de esas regiones (la barra de navegación, el contenido de la tarjeta, el grupo de botones dentro de un modal). Se complementan en lugar de competir.
flex-wrap: wrap puede hacer esto, pero los elementos en la misma fila visual no tienen relación entre sí — sus alturas son independientes. El dimensionamiento implícito de filas de Grid maneja esto automáticamente. Si necesitas que las tarjetas en una fila envuelta tengan todas la misma altura Y que sus elementos internos se alineen entre tarjetas, Grid es más limpio.Conclusión
El modelo mental de Flexbox es: elige una dirección, entiende qué propiedades controlan qué eje, luego elige si los elementos deben crecer, encogerse o quedar fijos. Una vez que eso encaja, la hoja de referencia se convierte en una consulta — no en una muleta. La guía Flexbox de MDN es la mejor referencia para casos límite, y la guía completa de CSS-Tricks sigue siendo la hoja de referencia visual más útil. Para uso en producción, el soporte de navegadores es esencialmente universal — no se necesitan prefijos. La especificación W3C vale la pena hojearla si alguna vez encuentras un caso límite genuinamente confuso — el algoritmo está documentado con precisión y responde la mayoría de las preguntas de "por qué se comporta así".