Saltar al contenido
grid.css · devschool

CSS Grid

Lección 13 de 25 · 9 min de lectura · Actualizado el

En esta lección
  1. Activar Grid y definir las columnas
  2. La unidad fr
  3. repeat() y minmax()
  4. La galería responsive: auto-fill y auto-fit
  5. gap: el espacio entre celdas
  6. Colocar un elemento en concreto: líneas y span
  7. Áreas con nombre: grid-template-areas
  8. El grid implícito
  9. Alinear en Grid
  10. subgrid en pocas palabras
  11. Errores frecuentes
  12. ¿Grid o Flexbox?
  13. Resumen

CSS Grid divide un contenedor en filas y columnas, como una tabla invisible, y te deja colocar cada elemento en las celdas que quieras. Es la herramienta ideal para el esqueleto de una página, galerías de fotos, paneles de control o cualquier diseño en el que las cosas deban quedar alineadas en dos direcciones a la vez.

Activar Grid y definir las columnas

Como en Flexbox, Grid se activa en el padre y afecta a sus hijos directos:

.galeria {
  display: grid;
  grid-template-columns: 200px 200px 200px; /* tres columnas de 200px */
  gap: 16px;                                /* separación entre celdas */
}

Los hijos de .galeria se colocan solos, uno en cada celda, de izquierda a derecha y bajando de fila cuando se acaban las columnas. No hace falta decir cuántas filas hay: se crean las que hagan falta.

grid-template-rows hace lo mismo con las filas:

.panel {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 80px 200px; /* primera fila de 80px, segunda de 200px */
}

La unidad fr

fr significa fracción del espacio libre. Es la unidad estrella de Grid:

grid-template-columns: 1fr 1fr 1fr; /* tres columnas iguales */
grid-template-columns: 2fr 1fr;     /* la primera mide el doble que la segunda */
grid-template-columns: 250px 1fr;   /* barra lateral fija y contenido que ocupa el resto */

¿Por qué no usar porcentajes? Porque fr se calcula después de restar los gap y las columnas fijas. Con 33.33% y un gap, las columnas suman más del 100 % y se desbordan. Con 1fr cuadra siempre.

Ejemplo numérico: un contenedor de 700px con grid-template-columns: 100px 1fr 2fr y sin gap. Quedan 600px libres, que se reparten en 3 fracciones de 200px. Las columnas miden 100px, 200px y 400px.

repeat() y minmax()

Para no repetir, usa repeat(veces, tamaño):

grid-template-columns: repeat(4, 1fr);         /* cuatro columnas iguales */
grid-template-columns: repeat(2, 100px 1fr);   /* = 100px 1fr 100px 1fr */

minmax(mínimo, máximo) da a una pista un tamaño flexible con límites:

grid-template-columns: minmax(150px, 250px) 1fr; /* lateral entre 150 y 250px */
grid-template-rows: minmax(100px, auto);         /* al menos 100px, más si el contenido lo pide */

La galería responsive: auto-fill y auto-fit

Esta línea crea tantas columnas como quepan, de al menos 200px cada una, sin media queries:

.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
}
  • minmax(200px, 1fr): cada columna mide como mínimo 200px y como máximo una fracción igual del espacio.
  • auto-fill: crea todas las columnas que quepan.

En un móvil saldrá una columna; en un portátil, cuatro o cinco.

auto-fill frente a auto-fit

Solo se diferencian cuando hay menos elementos que columnas posibles. Imagina un contenedor de 1000px y solo 2 tarjetas con minmax(200px, 1fr):

Columnas creadasResultado
auto-fill5 (3 quedan vacías)Las 2 tarjetas miden 200px y a la derecha hay hueco
auto-fit5, pero las vacías se colapsan a 0Las 2 tarjetas se estiran y miden 500px cada una

Regla práctica: auto-fill si quieres que las tarjetas mantengan un tamaño parecido aunque haya pocas; auto-fit si quieres que ocupen siempre todo el ancho.

Cuidado: si el contenedor mide menos que el mínimo (por ejemplo, 180px con minmax(200px, 1fr)), la columna se desborda. Se evita con minmax(min(200px, 100%), 1fr).

gap: el espacio entre celdas

gap: 16px;         /* igual entre filas y entre columnas */
gap: 24px 12px;    /* 24px entre filas, 12px entre columnas */
row-gap: 24px;
column-gap: 12px;

El gap solo va entre celdas, nunca en los bordes del contenedor. Para eso está el padding.

Colocar un elemento en concreto: líneas y span

Las líneas de la rejilla (los bordes entre columnas y filas) están numeradas empezando por 1. Con tres columnas hay cuatro líneas verticales. También se numeran al revés con negativos: -1 es la última.

.destacado {
  grid-column: 1 / 3;  /* de la línea 1 a la 3: ocupa dos columnas */
  grid-row: 1 / 2;     /* primera fila */
}

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

grid-column es el atajo de grid-column-start y grid-column-end. En vez de decir dónde acaba, puedes decir cuántas celdas ocupa con span:

.foto-grande {
  grid-column: span 2; /* dos columnas, empiece donde empiece */
  grid-row: span 2;    /* y dos filas */
}

span es muy cómodo en galerías, porque no obliga a saber en qué posición cae cada foto.

Líneas con nombre

Puedes poner nombre a las líneas escribiéndolo entre corchetes al definir las columnas:

.articulo {
  display: grid;
  grid-template-columns: [completo-inicio] 1fr [texto-inicio] minmax(0, 65ch) [texto-fin] 1fr [completo-fin];
}
.articulo > * { grid-column: texto; }             /* el texto, en la columna central */
.articulo > .imagen-ancha { grid-column: completo; } /* la imagen, a todo el ancho */

Si las líneas se llaman algo-inicio y algo-fin, Grid entiende grid-column: algo automáticamente. Es un patrón muy usado para blogs.

Áreas con nombre: grid-template-areas

Para el esqueleto de una página es más fácil dibujarlo con nombres:

.pagina {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "cabecera cabecera"
    "menu     contenido"
    "pie      pie";
}
header { grid-area: cabecera; }
nav    { grid-area: menu; }
main   { grid-area: contenido; }
footer { grid-area: pie; }

Cada línea entre comillas es una fila y cada palabra una celda. Si un nombre se repite, esa zona ocupa varias celdas. Un punto (.) deja una celda vacía.

La gran ventaja: para cambiar el diseño en el móvil, solo redibujas las áreas.

@media (max-width: 600px) {
  .pagina {
    grid-template-columns: 1fr;
    grid-template-areas:
      "cabecera"
      "contenido"
      "menu"
      "pie";
  }
}

Cuidado: cada área debe ser un rectángulo. Una forma en L no es válida y el navegador ignora toda la declaración.

El grid implícito

Lo que defines con grid-template-* es el grid explícito. Si hay más elementos que celdas, Grid crea filas nuevas automáticamente: es el grid implícito. Su tamaño se controla con grid-auto-rows:

.productos {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(150px, auto); /* cada fila nueva: al menos 150px */
}

grid-auto-flow

Decide cómo se colocan los elementos que no tienen posición:

grid-auto-flow: row;    /* rellena fila a fila (por defecto) */
grid-auto-flow: column; /* rellena columna a columna */
grid-auto-flow: dense;  /* rellena los huecos que dejen los elementos grandes */

Con dense, si una foto con span 2 no cabe al final de una fila y deja un hueco, Grid coloca ahí el siguiente elemento pequeño que quepa. Queda una galería compacta, tipo mosaico, pero el orden visual deja de coincidir con el del HTML.

Alinear en Grid

Grid tiene dos niveles de alineación.

Los elementos dentro de su celda (en el contenedor):

justify-items: start | end | center | stretch; /* horizontal */
align-items:   start | end | center | stretch; /* vertical */
place-items: center;                           /* atajo: los dos a la vez */

La rejilla completa dentro del contenedor, cuando la rejilla es más pequeña que él:

justify-content: center;       /* rejilla centrada en horizontal */
align-content: space-between;  /* filas repartidas en vertical */

Y un elemento suelto puede alinearse a su manera con justify-self y align-self. El valor por defecto es stretch: cada elemento llena su celda.

El truco más corto para centrar algo en CSS usa Grid:

.centrado { display: grid; place-items: center; min-height: 100vh; }

subgrid en pocas palabras

Con grid-template-columns: subgrid (o rows), un hijo que también es grid reutiliza las líneas del padre en lugar de crear las suyas. Así, los títulos, textos y botones de varias tarjetas quedan alineados entre sí aunque sus textos tengan distinta longitud:

.tarjetas { display: grid; grid-template-columns: repeat(3, 1fr); }
.tarjeta {
  display: grid;
  grid-row: span 3;             /* ocupa 3 filas del padre */
  grid-template-rows: subgrid;  /* título, texto y botón usan esas filas */
}

Funciona en todos los navegadores modernos desde 2023.

Errores frecuentes

  • Poner grid-column en el contenedor. Las propiedades de colocación van en los hijos.
  • Confundir celdas con líneas. grid-column: 1 / 3 ocupa dos columnas, no tres.
  • Usar porcentajes con gap y ver que la rejilla se desborda. Usa fr.
  • Áreas que no son rectángulos o filas con distinto número de palabras en grid-template-areas.
  • Olvidar que solo los hijos directos son elementos de la rejilla. Los nietos no se colocan en ella (salvo con subgrid).
  • Contenido que desborda una columna 1fr. 1fr equivale a minmax(auto, 1fr) y no encoge por debajo del contenido. Si una tabla o una URL larga rompen el diseño, usa minmax(0, 1fr).

¿Grid o Flexbox?

SituaciónMejor opción
Menú, barra de herramientas, botones en filaFlexbox
Esqueleto de la página (cabecera, lateral, contenido, pie)Grid
Galería con columnas alineadasGrid
Elementos de tamaño variable que deben fluirFlexbox
Formulario con etiquetas y campos alineadosGrid

La idea clave: con Flexbox el contenido decide el tamaño; con Grid tú decides la rejilla y el contenido se adapta a ella. No compiten: lo habitual es un Grid para la página y Flexbox dentro de cada bloque.

Resumen

PropiedadDóndePara qué
display: gridPadreActiva Grid
grid-template-columns / -rowsPadreDefine columnas y filas (fr, repeat, minmax)
grid-template-areasPadreDibuja zonas con nombre
gapPadreEspacio entre celdas
grid-auto-rows / grid-auto-flowPadreControla el grid implícito
justify-items / align-items / place-itemsPadreAlinea los elementos en sus celdas
grid-column / grid-rowHijoColoca por líneas o con span
grid-areaHijoColoca en un área con nombre
justify-self / align-selfHijoAlineación propia

Pruébalo tú

Cambia el código y pulsa Ejecutar (o Ctrl + Enter).

grid.html
Resultado

Pon a prueba lo que has aprendido

[CSS] ¿Qué crea este código?
.galeria {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

[CSS] ¿Qué significa la unidad fr en Grid?

[CSS] ¿Qué hace grid-column: 1 / -1?

[CSS] El contenedor mide 700px y tiene gap: 16px. ¿Cuántas columnas se crean?
.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

[CSS] ¿Qué ocurre con este grid-template-areas?
.pagina {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "cabecera cabecera"
    "menu contenido";
}
header { grid-area: cabecera; }

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.