Skip to content

CSS Grid a fondo ​

Si Flexbox es una repisa, Grid es un tablero de ajedrez: controlas filas y columnas al mismo tiempo. Con Grid puedes crear el layout completo de una página, galerías tipo revista o dashboards con muy poco código, y que se adapten solos a cualquier pantalla. Es la herramienta más poderosa de maquetado de CSS.

Concepto ​

Grid divide un contenedor en una cuadrícula de filas y columnas, y coloca a los hijos en sus celdas (o les permite ocupar varias).

txt
        línea 1   línea 2   línea 3   línea 4
          │         │         │         │
 línea 1 ─┼─────────┼─────────┼─────────┤
          │ celda   │         │         │  ← fila (track)
 línea 2 ─┼─────────┼─────────┼─────────┤
          │         │  área de 2×1      │
 línea 3 ─┼─────────┼───────────────────┤
          ▲
       columna (track)       ↔ gap: espacio entre tracks

Vocabulario:

  • Líneas: las divisiones numeradas (empiezan en 1). También hay números negativos desde el final (-1 es la última).
  • Track: una fila o columna.
  • Celda: la intersección de una fila y una columna.
  • Área: un rectángulo de una o varias celdas.

Analogía

Una hoja de cálculo: defines cuántas columnas hay y de qué ancho, y cada dato ocupa una celda o puedes "combinar celdas" para que ocupe varias.

Tu primera grilla ​

html
<div class="grid">
  <div>1</div><div>2</div><div>3</div>
  <div>4</div><div>5</div><div>6</div>
</div>
css
.grid {
  display: grid;
  grid-template-columns: 200px 200px 200px;  /* 3 columnas de 200px */
  gap: 1rem;
}

Los ítems se colocan automáticamente de izquierda a derecha, creando nuevas filas cuando hace falta.

Experimenta con las principales propiedades:

Grid interactivo

Definir columnas y filas ​

La unidad fr ​

fr (fracción) reparte el espacio disponible:

css
.grid {
  grid-template-columns: 1fr 1fr 1fr;   /* 3 columnas iguales */
  grid-template-columns: 2fr 1fr;       /* la primera mide el doble */
  grid-template-columns: 250px 1fr;     /* barra lateral fija + contenido flexible */
  grid-template-columns: 1fr auto 1fr;  /* la del medio mide lo que su contenido */
}

repeat() ​

css
.grid {
  grid-template-columns: repeat(4, 1fr);           /* = 1fr 1fr 1fr 1fr */
  grid-template-columns: repeat(2, 100px 1fr);     /* = 100px 1fr 100px 1fr */
}

minmax() ​

Define un tamaño mínimo y máximo para un track:

css
.grid {
  grid-template-columns: minmax(200px, 300px) 1fr;
  grid-template-rows: minmax(100px, auto);   /* al menos 100px, crece con el contenido */
}

Filas ​

css
.grid {
  grid-template-rows: 80px 1fr 60px;   /* header, contenido, footer */
  grid-auto-rows: 200px;               /* altura de las filas creadas automáticamente */
  grid-auto-rows: minmax(150px, auto);
}

La línea mágica: auto-fit + minmax ​

Una galería responsive sin una sola media query:

css
.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1.5rem;
}

Se lee así: "crea tantas columnas como quepan, cada una de al menos 250px y que se repartan el espacio sobrante (1fr)". En un celular verás 1 columna, en una tablet 2 o 3, en escritorio 4 o más.

  • auto-fit: si sobran columnas vacías, las colapsa y los ítems se estiran para llenar la fila.
  • auto-fill: conserva las columnas vacías; los ítems mantienen su tamaño.

La diferencia sólo se nota cuando hay pocos ítems: con 2 tarjetas en una pantalla ancha, auto-fit las estira a todo el ancho y auto-fill las deja a la izquierda con su tamaño.

Error común

En pantallas menores que el mínimo (por ejemplo, 250px en un móvil de 320px con padding), la columna se desborda. Solución robusta:

css
grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
Galería con auto-fit y minmax

Colocar ítems ​

Por líneas ​

css
.destacado {
  grid-column: 1 / 3;     /* de la línea 1 a la 3 (ocupa 2 columnas) */
  grid-row: 1 / 2;
}

.ancho-completo {
  grid-column: 1 / -1;    /* de la primera a la última línea: toda la fila */
}

Con span ​

css
.tarjeta-grande {
  grid-column: span 2;    /* ocupa 2 columnas desde donde le toque */
  grid-row: span 2;       /* y 2 filas */
}

grid-area (atajo) ​

css
.item {
  grid-area: 1 / 1 / 3 / 4;  /* fila-inicio / columna-inicio / fila-fin / columna-fin */
}

grid-template-areas: dibuja tu layout ​

La forma más legible de definir un layout: le pones nombre a cada zona y "dibujas" la cuadrícula con texto.

html
<div class="pagina">
  <header class="header">Header</header>
  <nav class="nav">Menú</nav>
  <main class="main">Contenido</main>
  <aside class="aside">Lateral</aside>
  <footer class="footer">Footer</footer>
</div>
css
.pagina {
  display: grid;
  grid-template-columns: 200px 1fr 220px;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header header"
    "nav    main   aside"
    "footer footer footer";
  min-height: 100vh;
  gap: 1rem;
}

.header { grid-area: header; }
.nav    { grid-area: nav; }
.main   { grid-area: main; }
.aside  { grid-area: aside; }
.footer { grid-area: footer; }

Reglas: cada fila entre comillas, todas con el mismo número de columnas, las áreas deben ser rectangulares y un punto . indica una celda vacía.

Lo mejor: para hacerlo responsive sólo cambias el "dibujo" en una media query:

css
/* Móvil primero: una sola columna */
.pagina {
  display: grid;
  grid-template-areas:
    "header"
    "nav"
    "main"
    "aside"
    "footer";
}

@media (min-width: 900px) {
  .pagina {
    grid-template-columns: 200px 1fr 220px;
    grid-template-areas:
      "header header header"
      "nav    main   aside"
      "footer footer footer";
  }
}
Layout con grid-template-areas

Alineación en Grid ​

css
.grid {
  /* Alinea cada ítem DENTRO de su celda */
  justify-items: stretch;   /* horizontal: start | center | end | stretch */
  align-items: stretch;     /* vertical */
  place-items: center;      /* atajo: align-items + justify-items */

  /* Alinea la grilla completa dentro del contenedor (si sobra espacio) */
  justify-content: center;  /* start | center | end | space-between ... */
  align-content: center;
}

.item {
  justify-self: end;        /* sólo este ítem */
  align-self: start;
  place-self: center;
}

Grid implícito vs. explícito ​

  • Explícito: las filas y columnas que defines con grid-template-*.
  • Implícito: las que Grid crea automáticamente cuando hay más ítems que celdas.
css
.grid {
  grid-template-columns: repeat(3, 1fr);  /* explícito: 3 columnas */
  grid-auto-rows: 180px;                  /* implícito: cada fila nueva mide 180px */
  grid-auto-flow: row;                    /* por defecto: llena por filas */
  grid-auto-flow: dense;                  /* rellena huecos que dejan ítems grandes */
}

dense es ideal para galerías tipo mosaico, pero altera el orden visual: no lo uses si el orden importa.

Líneas con nombre ​

css
.grid {
  grid-template-columns:
    [completo-inicio] minmax(1rem, 1fr)
    [contenido-inicio] minmax(0, 1100px) [contenido-fin]
    minmax(1rem, 1fr) [completo-fin];
}

.grid > *           { grid-column: contenido; }  /* todo centrado a 1100px máx. */
.grid > .ancho-full { grid-column: completo; }   /* esta sección ocupa todo el ancho */

Este patrón permite que el contenido esté centrado pero ciertas secciones (un banner, una imagen) lleguen de borde a borde. Muy usado en blogs y landing pages.

Subgrid ​

Con subgrid, un ítem que también es grid hereda las líneas de su padre. Resuelve el problema de alinear partes internas de tarjetas distintas (títulos de diferente largo):

css
.tarjetas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1.5rem;
}

.tarjeta {
  display: grid;
  grid-row: span 3;                 /* cada tarjeta ocupa 3 filas: imagen, título, texto */
  grid-template-rows: subgrid;      /* usa las filas del padre */
  gap: 0.75rem;
}

Así todos los títulos empiezan a la misma altura y todos los textos también, aunque un título ocupe dos líneas. Soportado en todos los navegadores modernos desde 2023.

Patrones reales ​

Holy grail (página clásica) ​

Ya lo viste con grid-template-areas. Añade min-height: 100vh y grid-template-rows: auto 1fr auto para que el footer quede siempre abajo.

Sección de características: texto + imagen ​

css
.feature {
  display: grid;
  gap: 2rem;
  align-items: center;
}

@media (min-width: 768px) {
  .feature {
    grid-template-columns: 1fr 1fr;
  }
  .feature--invertida .feature__imagen {
    order: -1;   /* alterna la imagen a la izquierda */
  }
}

Imagen con texto encima (superposición sin position) ​

css
.banner {
  display: grid;
}

.banner > * {
  grid-area: 1 / 1;   /* imagen y texto en la misma celda: se superponen */
}

.banner__texto {
  align-self: end;
  padding: 2rem;
  color: #fff;
  background: linear-gradient(transparent, rgb(0 0 0 / 0.7));
}

Dashboard ​

css
.dashboard {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(140px, auto);
  gap: 1rem;
}
.dashboard .grafica-principal { grid-column: span 3; grid-row: span 2; }
.dashboard .resumen          { grid-row: span 2; }

@media (max-width: 800px) {
  .dashboard { grid-template-columns: 1fr 1fr; }
  .dashboard .grafica-principal { grid-column: 1 / -1; }
}

Buena práctica

En las DevTools de Chrome y Firefox, haz clic en la etiqueta grid junto al elemento en el panel Elements: se dibujan las líneas, números y nombres de áreas sobre la página. Es la mejor forma de depurar layouts.

Ejercicios ​

  1. Crea una grilla de 4 columnas iguales con 20px de separación.
  2. Haz una galería responsive sin media queries con tarjetas de mínimo 220px.
  3. En una grilla de 3 columnas, haz que el primer ítem ocupe toda la primera fila.
  4. Crea un layout con grid-template-areas: en escritorio, header arriba, sidebar a la izquierda (250px), contenido a la derecha y footer abajo; en móvil, todo en una columna.
  5. Centra un elemento en la pantalla con sólo 3 propiedades.
Ver solución
css
/* 1 */
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}

/* 2 */
.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 1rem;
}

/* 3 */
.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
.grid-3 > :first-child {
  grid-column: 1 / -1;
}

/* 4 */
.layout {
  display: grid;
  min-height: 100vh;
  grid-template-rows: auto 1fr auto auto;
  grid-template-areas:
    "header"
    "contenido"
    "sidebar"
    "footer";
}
.layout header  { grid-area: header; }
.layout aside   { grid-area: sidebar; }
.layout main    { grid-area: contenido; }
.layout footer  { grid-area: footer; }

@media (min-width: 768px) {
  .layout {
    grid-template-columns: 250px 1fr;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
      "header  header"
      "sidebar contenido"
      "footer  footer";
  }
}

/* 5 */
body {
  display: grid;
  place-items: center;
  min-height: 100vh;
}

Resumen ​

  • Grid organiza en dos dimensiones: filas y columnas.
  • fr reparte el espacio libre; repeat() y minmax() simplifican las definiciones.
  • repeat(auto-fit, minmax(min(250px, 100%), 1fr)) = galería responsive sin media queries.
  • Coloca ítems con líneas (1 / -1), span o áreas con nombre.
  • grid-template-areas permite "dibujar" el layout y cambiarlo fácilmente en cada breakpoint.
  • place-items: center centra; subgrid alinea el interior de tarjetas.
  • Usa el inspector de Grid de las DevTools para depurar.

Siguiente: Responsive design.

Academia Web — aprende, copia y construye.