Flexbox y CSS Grid son las dos herramientas modernas de maquetación en CSS. Antes de que existieran, los layouts se hacían con floats, tablas y posicionamiento absoluto: técnicas llenas de hacks y comportamientos impredecibles. Hoy, Flexbox y Grid cubren prácticamente todos los casos de diseño de forma limpia y declarativa.
Muchos principiantes los tratan como alternativas equivalentes y usan uno u otro de forma aleatoria. En realidad tienen propósitos distintos y complementarios. En esta guía aprenderás la diferencia fundamental, cuándo usar cada uno y cómo combinarlos en layouts reales.
La diferencia fundamental
Flexbox es unidimensional: organiza elementos en una sola dirección, ya sea en fila o en columna. Es perfecto para distribuir elementos a lo largo de un eje: centrar un botón, distribuir los ítems de una barra de navegación, alinear iconos con texto.
CSS Grid es bidimensional: organiza elementos en filas Y columnas al mismo tiempo. Es perfecto para definir la estructura global de una página o una sección compleja donde los elementos deben alinearse tanto horizontal como verticalmente.
/* La pregunta que debes hacerte:
¿Necesito controlar el layout en UNA dirección o en DOS?
Una dirección (fila O columna) → Flexbox
Dos direcciones (filas Y columnas) → Grid */
Dicho de otra manera: Flexbox parte de los elementos y los distribuye en el espacio disponible. Grid parte del espacio y coloca los elementos en él.
Flexbox: conceptos fundamentales
Flexbox trabaja con dos actores: el contenedor flex (el elemento con display: flex) y los ítems flex (sus hijos directos).
/* Activar Flexbox en el contenedor */
.contenedor {
display: flex;
/* Dirección del eje principal */
flex-direction: row; /* → fila (por defecto) */
/* flex-direction: column; ↓ columna */
/* flex-direction: row-reverse; ← fila invertida */
/* flex-direction: column-reverse; ↑ columna invertida */
/* Alineación en el eje PRINCIPAL (horizontal si row, vertical si column) */
justify-content: flex-start; /* al inicio (por defecto) */
justify-content: flex-end; /* al final */
justify-content: center; /* centrado */
justify-content: space-between; /* espacio entre elementos, sin margen en los bordes */
justify-content: space-around; /* espacio alrededor de cada elemento */
justify-content: space-evenly; /* espacio igual entre todos, incluyendo bordes */
/* Alineación en el eje CRUZADO (vertical si row, horizontal si column) */
align-items: stretch; /* ocupa todo el alto (por defecto) */
align-items: flex-start; /* al inicio del eje cruzado */
align-items: flex-end; /* al final del eje cruzado */
align-items: center; /* centrado en el eje cruzado */
align-items: baseline; /* alineado por la línea base del texto */
/* Salto de línea cuando no caben los ítems */
flex-wrap: nowrap; /* no saltar (por defecto, puede causar desbordamiento) */
flex-wrap: wrap; /* saltar a la siguiente línea */
/* gap: espacio entre ítems (más limpio que usar margin) */
gap: 16px; /* igual en filas y columnas */
gap: 8px 16px; /* fila columna */
}
/* Propiedades en los ÍTEMS flex */
.item {
/* flex-grow: cuánto crece el ítem en el espacio sobrante */
flex-grow: 0; /* no crece (por defecto) */
flex-grow: 1; /* crece para llenar el espacio disponible */
/* Si dos ítems tienen flex-grow: 1, reparten el espacio a partes iguales */
/* Si uno tiene flex-grow: 2 y otro flex-grow: 1, el primero ocupa el doble */
/* flex-shrink: cuánto se encoge si no hay espacio */
flex-shrink: 1; /* se encoge (por defecto) */
flex-shrink: 0; /* no se encoge nunca (mantiene su tamaño) */
/* flex-basis: tamaño base antes de aplicar grow/shrink */
flex-basis: auto; /* usa su tamaño natural (por defecto) */
flex-basis: 200px; /* tamaño base de 200px */
/* Atajo: flex: grow shrink basis */
flex: 1; /* equivale a flex: 1 1 0% (el más usado) */
flex: auto; /* equivale a flex: 1 1 auto */
flex: none; /* equivale a flex: 0 0 auto (tamaño fijo) */
/* align-self: sobrescribe align-items solo para este ítem */
align-self: center;
/* order: cambia el orden visual sin modificar el HTML */
order: -1; /* va antes que los demás */
order: 1; /* va después de los que tienen order: 0 */
}
Casos de uso de Flexbox
Centrar un elemento (horizontal y verticalmente)
/* El caso más habitual y más buscado */
.contenedor {
display: flex;
justify-content: center; /* centrar horizontalmente */
align-items: center; /* centrar verticalmente */
min-height: 100vh; /* necesitas altura para que el centrado vertical tenga efecto */
}
Barra de navegación
/* Logo a la izquierda, enlaces a la derecha */
.navbar {
display: flex;
justify-content: space-between; /* logo izquierda, links derecha */
align-items: center; /* centrar verticalmente */
padding: 0 24px;
height: 64px;
}
.navbar__logo { flex-shrink: 0; } /* el logo no se encoge */
.navbar__links {
display: flex;
gap: 24px;
list-style: none;
}
Tarjeta con footer pegado al fondo
/* El botón siempre está al fondo de la tarjeta aunque el contenido varíe */
.tarjeta {
display: flex;
flex-direction: column; /* apilar verticalmente */
height: 100%; /* ocupar todo el alto del padre */
}
.tarjeta__cuerpo {
flex: 1; /* el cuerpo crece para llenar el espacio disponible */
}
.tarjeta__footer {
flex-shrink: 0; /* el footer mantiene su tamaño */
/* o simplemente: margin-top: auto también funciona */
}
Distribuir ítems con espacio igual
/* Pestañas o pasos de un proceso */
.tabs {
display: flex;
gap: 4px;
}
.tab {
flex: 1; /* cada pestaña ocupa la misma proporción */
text-align: center;
padding: 12px;
}
CSS Grid: conceptos fundamentales
Grid trabaja definiendo una cuadrícula en el contenedor y luego colocando los ítems en ella.
/* Definir el grid en el contenedor */
.contenedor {
display: grid;
/* Columnas: definir cuántas y de qué ancho */
grid-template-columns: 200px 1fr 1fr;
/* Tres columnas: la primera de 200px fijos, las otras dos reparten el espacio a partes iguales */
grid-template-columns: repeat(3, 1fr);
/* Tres columnas iguales (atajo con repeat) */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
/* Las columnas se crean automáticamente para caber en el ancho disponible
cada una de al menos 250px. El número de columnas se ajusta al viewport. */
/* Filas: definir su altura */
grid-template-rows: auto 1fr auto;
/* header auto (su altura natural), main ocupa el resto, footer auto */
/* Espacio entre celdas */
gap: 24px;
gap: 16px 24px; /* fila columna */
/* Alineación de los ítems dentro de sus celdas */
justify-items: stretch; /* ancho de la celda (por defecto) */
align-items: stretch; /* alto de la celda (por defecto) */
justify-items: center; /* centrado horizontalmente en la celda */
align-items: center; /* centrado verticalmente en la celda */
/* Alineación del grid completo dentro del contenedor */
justify-content: center;
align-content: center;
}
/* Colocar ítems en el grid */ .item { /* Por posición de línea */ grid-column: 1 / 3; /* desde la línea 1 hasta la 3 (ocupa 2 columnas) */ grid-row: 2 / 4; /* desde la línea 2 hasta la 4 (ocupa 2 filas) */ /* Con span: indicar cuántas celdas ocupa en lugar de las líneas */ grid-column: span 2; /* ocupa 2 columnas desde su posición actual */ grid-row: span 3; /* ocupa 3 filas */ /* Ocupar toda la fila */ grid-column: 1 / -1; /* desde la primera hasta la última línea */ /* align-self y justify-self: alineación individual */ align-self: center; justify-self: end; }
Áreas con nombre: la forma más legible
/* grid-template-areas: define la estructura como un mapa visual */
.pagina {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 64px 1fr 60px;
grid-template-areas:
"header header" /* el header ocupa las dos columnas */
"sidebar main " /* sidebar izquierda, main derecha */
"footer footer"; /* el footer ocupa las dos columnas */
min-height: 100vh;
gap: 0;
}
/* Asignar cada elemento a su área */
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
/* El HTML es limpio y el CSS describe visualmente la estructura */
Casos de uso de Grid
Layout de página completo
/* Layout clásico con header, sidebar, main y footer */
.app {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: 60px 1fr 50px;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
height: 100vh;
}
.header { grid-area: header; background: #1e293b; }
.sidebar { grid-area: sidebar; background: #f1f5f9; }
.main { grid-area: main; padding: 24px; overflow-y: auto; }
.footer { grid-area: footer; background: #1e293b; }
Galería de imágenes responsive
/* Cuadrícula que se adapta al ancho disponible automáticamente */
.galeria {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
/* En pantallas anchas: 4-5 columnas
En tablets: 3 columnas
En móvil: 2 columnas (o 1 si las imágenes son de 200px mínimo)
Todo sin media queries */
.galeria img {
width: 100%;
aspect-ratio: 1; /* cuadradas */
object-fit: cover;
}
Tarjetas con grid de 12 columnas
/* Sistema de columnas al estilo Bootstrap pero con Grid nativo */ .fila { display: grid; grid-template-columns: repeat(12, 1fr); gap: 24px; } /* En desktop: tres columnas iguales (4+4+4 = 12) */ .col-4 { grid-column: span 4; } /* En tablet: dos columnas (6+6 = 12) */ @media (max-width: 768px) { .col-4 { grid-column: span 6; } } /* En móvil: una columna (12) */ @media (max-width: 480px) { .col-4 { grid-column: span 12; } }
Grid asimétrico: artículo destacado
/* Un artículo grande a la izquierda, dos pequeños apilados a la derecha */
.noticias {
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-rows: repeat(2, 200px);
gap: 16px;
}
.noticia-principal {
grid-row: span 2; /* ocupa las dos filas */
}
/* Primera noticia secundaria */
.noticia-secundaria:nth-child(2) { grid-column: 2; grid-row: 1; }
.noticia-secundaria:nth-child(3) { grid-column: 2; grid-row: 2; }
Cómo combinarlos: Grid para el layout, Flexbox para los componentes
La forma más efectiva de usar ambos es combinarlos: Grid define la estructura macro de la página, y Flexbox organiza los elementos dentro de cada componente. No son rivales: se complementan.
/* Grid para la estructura de la página */
.app {
display: grid;
grid-template-areas:
"header"
"main"
"footer";
grid-template-rows: 60px 1fr 50px;
min-height: 100vh;
}
/* Flexbox dentro del header para distribuir su contenido */
.header {
grid-area: header;
display: flex; /* ← Flexbox dentro del Grid */
justify-content: space-between;
align-items: center;
padding: 0 24px;
}
/* Grid para la cuadrícula de tarjetas en el main */
.main {
grid-area: main;
display: grid; /* ← Grid anidado */
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
padding: 24px;
align-content: start;
}
/* Flexbox dentro de cada tarjeta */
.tarjeta {
display: flex; /* ← Flexbox dentro del Grid */
flex-direction: column;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,.1);
}
.tarjeta__cuerpo {
flex: 1;
padding: 16px;
}
.tarjeta__footer {
padding: 12px 16px;
display: flex; /* ← Flexbox anidado */
justify-content: space-between;
align-items: center;
}
Tabla de decisión rápida
| Situación | Usa |
|---|---|
| Centrar un elemento | Flexbox |
| Barra de navegación con logo y enlaces | Flexbox |
| Alinear un icono con texto | Flexbox |
| Botones en línea con espacio entre ellos | Flexbox |
| Tarjeta con footer pegado al fondo | Flexbox (column) |
| Layout de página completo (header, sidebar, main, footer) | Grid |
| Galería de imágenes responsive | Grid (auto-fill + minmax) |
| Cuadrícula de tarjetas de productos | Grid |
| Layout asimétrico (artículo grande + pequeños) | Grid |
| Sistema de columnas tipo Bootstrap | Grid |
| Distribuir contenido dentro de una tarjeta | Flexbox (dentro de un Grid) |
El truco del auto-fill con minmax: responsive sin media queries
Una de las combinaciones más potentes de Grid es repeat(auto-fill, minmax(min, 1fr)). Crea automáticamente tantas columnas como quepan en el ancho disponible, cada una con un mínimo de min y creciendo para repartir el espacio sobrante. No necesitas media queries.
/* Cuadrícula completamente adaptable */
.productos {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 20px;
}
/* Comportamiento:
Viewport > 1100px → 4 columnas (~275px cada una)
Viewport 780-1099px → 3 columnas
Viewport 520-779px → 2 columnas
Viewport < 520px → 1 columna
Todo sin escribir ni una media query */
/* auto-fit vs auto-fill:
auto-fill: crea columnas vacías si hay espacio (los ítems no se estiran de más)
auto-fit: colapsa las columnas vacías (los ítems sí se estiran para llenar)
En la mayoría de casos, auto-fill es el comportamiento más predecible */
Resumen
- Flexbox es unidimensional: organiza elementos en una fila o en una columna. Es la herramienta correcta para distribuir elementos a lo largo de un eje, centrar contenido y construir componentes como navbars, botones o tarjetas.
- CSS Grid es bidimensional: organiza elementos en filas y columnas al mismo tiempo. Es la herramienta correcta para definir la estructura global de una página, galerías, cuadrículas de tarjetas y cualquier layout donde los elementos deben alinearse en dos dimensiones.
- La regla práctica: si piensas en el layout como una cuadrícula, usa Grid. Si piensas en cómo distribuir elementos en una línea, usa Flexbox.
- No son excluyentes: el patrón más efectivo es usar Grid para el layout de la página y Flexbox para organizar el contenido dentro de cada componente.
repeat(auto-fill, minmax(min, 1fr))crea layouts responsive sin media queries: el número de columnas se ajusta automáticamente al ancho disponible.grid-template-areases la forma más legible de definir un layout complejo: el CSS refleja visualmente la estructura de la página.
No hay comentarios todavía. Sé el primero en compartir tu opinión.