Tema
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 tracksVocabulario:
- Líneas: las divisiones numeradas (empiezan en 1). También hay números negativos desde el final (
-1es 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:
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));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";
}
}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
- Crea una grilla de 4 columnas iguales con 20px de separación.
- Haz una galería responsive sin media queries con tarjetas de mínimo 220px.
- En una grilla de 3 columnas, haz que el primer ítem ocupe toda la primera fila.
- 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. - 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.
frreparte el espacio libre;repeat()yminmax()simplifican las definiciones.repeat(auto-fit, minmax(min(250px, 100%), 1fr))= galería responsive sin media queries.- Coloca ítems con líneas (
1 / -1),spano áreas con nombre. grid-template-areaspermite "dibujar" el layout y cambiarlo fácilmente en cada breakpoint.place-items: centercentra;subgridalinea el interior de tarjetas.- Usa el inspector de Grid de las DevTools para depurar.
Siguiente: Responsive design.