CSS Grid vs Flexbox: cuándo usar cada uno con ejemplos

D
DanisCh
• 10 min de lectura
CSS Grid vs Flexbox: cuándo usar cada uno con ejemplos
HTML JavaScript

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ónUsa
Centrar un elementoFlexbox
Barra de navegación con logo y enlacesFlexbox
Alinear un icono con textoFlexbox
Botones en línea con espacio entre ellosFlexbox
Tarjeta con footer pegado al fondoFlexbox (column)
Layout de página completo (header, sidebar, main, footer)Grid
Galería de imágenes responsiveGrid (auto-fill + minmax)
Cuadrícula de tarjetas de productosGrid
Layout asimétrico (artículo grande + pequeños)Grid
Sistema de columnas tipo BootstrapGrid
Distribuir contenido dentro de una tarjetaFlexbox (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-areas es la forma más legible de definir un layout complejo: el CSS refleja visualmente la estructura de la página.

¿Te ha gustado esta entrada?

Compártela con tus compañeros para que también sigan aprendiendo.

Comunidad y Comentarios

0 COMENTARIOS

No hay comentarios todavía. Sé el primero en compartir tu opinión.

Escribe tu opinión
Respondiendo a