0 Comentarios
CSS Grid es un sistema de maquetación de CSS pensado para organizar contenido en filas y columnas. Con unas pocas reglas puedes construir desde una galería de tarjetas hasta la estructura completa de una página, controlar el espacio entre bloques y adaptar el resultado a distintos anchos de pantalla.
En esta guía vamos a crear un layout responsive desde cero. Empezaremos por una cuadrícula básica, añadiremos columnas flexibles, aprenderemos a colocar zonas con nombre y terminaremos con una página que cambia de estructura en móvil. Puedes copiar cada ejemplo y modificarlo mientras avanzas.
| Si quieres conseguir… | Empieza por… |
|---|---|
| Varias columnas del mismo ancho | repeat(3, 1fr) |
| Tarjetas que se adapten solas | repeat(auto-fit, minmax(16rem, 1fr)) |
| Separación entre filas y columnas | gap |
| Una estructura con cabecera, menú y contenido | grid-template-areas |
| Centrar el contenido de las celdas | place-items |
| Cambiar la distribución en móvil | Una media query que redefina columnas o áreas |
Grid se diferencia de otros métodos de maquetación por trabajar en dos dimensiones. El navegador puede coordinar las filas y las columnas a la vez, por lo que cada bloque encaja en una cuadrícula común. Esto resulta especialmente útil en layouts de página, galerías, listados de productos, paneles y composiciones con zonas bien definidas.
Al declarar display: grid, el elemento se convierte en contenedor grid y sus hijos directos pasan a ser elementos grid. A partir de ahí puedes decidir cuántas columnas habrá, cuánto medirán, qué separación existirá entre ellas y dónde se colocará cada elemento.
Grid no sustituye a Flexbox. Flexbox suele encajar mejor cuando el contenido avanza en una sola dirección (una fila de botones o los elementos de un menú), mientras que Grid aporta más control cuando filas y columnas deben relacionarse entre sí. En una web real es habitual usar Grid para la estructura general y Flexbox dentro de sus componentes.
Estos conceptos parecen más complicados de lo que son. Imagina una hoja cuadriculada:
Línea: límite horizontal o vertical que separa las pistas. Una cuadrícula de tres columnas tiene cuatro líneas verticales.
Pista: espacio comprendido entre dos líneas; puede ser una fila o una columna.
Celda: intersección de una fila y una columna.
Área: conjunto rectangular de una o varias celdas.
Gap: espacio entre pistas. No hace falta simularlo con márgenes en cada elemento.
Cuadrícula explícita: filas y columnas que declaras con grid-template-columns y grid-template-rows.
Cuadrícula implícita: pistas que el navegador crea cuando hay más elementos de los previstos.
Esta distinción ayuda a entender por qué algunas propiedades se aplican al padre y otras a los hijos:
| Propiedad | Se aplica a | Para qué sirve |
display: grid |
Contenedor | Activa el contexto de cuadrícula |
grid-template-columns |
Contenedor | Define las columnas explícitas |
grid-template-rows |
Contenedor | Define las filas explícitas |
gap |
Contenedor | Separa filas y columnas |
grid-template-areas |
Contenedor | Dibuja una distribución mediante nombres |
grid-column y grid-row |
Elemento | Colocan o expanden un hijo entre líneas |
grid-area |
Elemento | Asigna un hijo a un área con nombre |
place-items |
Contenedor | Alinea el contenido dentro de las celdas |
Empezaremos con seis tarjetas. Grid no exige clases distintas para cada una si quieres que el navegador las coloque automáticamente.
<section class="tarjetas">
<article class="tarjeta">Proyecto 1</article>
<article class="tarjeta">Proyecto 2</article>
<article class="tarjeta">Proyecto 3</article>
<article class="tarjeta">Proyecto 4</article>
<article class="tarjeta">Proyecto 5</article>
<article class="tarjeta">Proyecto 6</article>
</section>
El section será el contenedor y cada article, un elemento grid. Los nietos que pudieran existir dentro de cada tarjeta no se colocan en esta cuadrícula; pertenecen al flujo interno de su tarjeta.
Para crear la cuadrícula más básica bastan dos declaraciones:
.tarjetas {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
fr representa una fracción del espacio disponible. Al escribir tres veces 1fr, el navegador reparte el ancho en tres columnas iguales. La misma regla puede expresarse de forma más compacta:
.tarjetas {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
Ahora añadimos separación. gap crea espacio solo entre las pistas, sin añadir margen en los bordes exteriores del contenedor.
.tarjetas {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
También puedes controlar cada eje por separado con column-gap y row-gap, aunque una sola medida suele bastar para mantener un ritmo uniforme.
fr, repeat() y minmax()Las columnas iguales funcionan bien en una demo, pero un layout real necesita límites. minmax() permite indicar el tamaño mínimo y máximo de una pista:
.tarjetas {
display: grid;
grid-template-columns: repeat(3, minmax(14rem, 1fr));
gap: 1.5rem;
}
Cada columna intentará medir al menos 14rem y podrá crecer hasta ocupar una fracción del espacio libre. Si el contenedor no tiene sitio para las tres, esta versión puede provocar desbordamiento: el número de columnas sigue fijado en tres.
Otra combinación habitual mezcla una zona lateral estable con un contenido que aprovecha el resto del ancho:
.pagina {
display: grid;
grid-template-columns: minmax(14rem, 18rem) minmax(0, 1fr);
gap: 2rem;
}
El segundo minmax(0, 1fr) tiene un detalle importante. El 0 permite que la pista se encoja aunque su contenido tenga un ancho intrínseco mayor. Sin ese límite, una tabla, una URL larga o un bloque de código puede empujar la columna y generar scroll horizontal.
Grid reparte el espacio del contenedor, no decide por sí solo cuánto debe medir este. Si necesitas limitar el ancho total de la composición, puedes combinarlo con la propiedad max-width en CSS y centrar el contenedor con margin-inline: auto.
Una galería de tarjetas no siempre necesita puntos de ruptura. auto-fit permite que el navegador calcule cuántas columnas caben según el ancho disponible:
.tarjetas {
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(min(100%, 16rem), 1fr)
);
gap: clamp(1rem, 2vw, 1.5rem);
}
Esta regla combina tres decisiones:
auto-fit crea tantas columnas como quepan.
minmax() evita que una columna baje del mínimo previsto y le permite crecer.
min(100%, 16rem) impide que el mínimo de 16rem desborde un móvil más estrecho.
Con suficiente espacio aparecerán varias columnas. Al reducirse el contenedor, las tarjetas pasarán a dos y luego a una sin que tengas que indicar anchos de dispositivo.
auto-fit y auto-fillAmbos valores calculan el número de pistas posibles. La diferencia aparece cuando sobran huecos:
auto-fit colapsa las pistas vacías y deja que las columnas existentes aprovechen ese espacio.
auto-fill conserva el espacio de las pistas que podrían existir aunque no haya elementos para llenarlas.
Para una colección de tarjetas que debe ocupar todo el ancho, auto-fit suele dar el resultado esperado. auto-fill es útil cuando quieres conservar la cuadrícula imaginaria y evitar que los pocos elementos disponibles se estiren.
Esta técnica resuelve bien componentes repetitivos, pero no todas las decisiones responsive. Si en móvil necesitas mover una navegación, ocultar una zona secundaria o alterar la jerarquía visual, tendrás que definir un cambio explícito. La guía sobre media queries y diseño responsive explica cómo elegir y organizar esos puntos de ruptura.
grid-template-areasLas áreas con nombre permiten describir la página de una forma muy visual. Partimos de una estructura semántica:
<div class="layout">
<header class="cabecera">Cabecera</header>
<nav class="lateral">Navegación</nav>
<main class="contenido">Contenido principal</main>
<aside class="relacionado">Contenido relacionado</aside>
<footer class="pie">Pie de página</footer>
</div>
Después dibujamos tres columnas y tres filas en CSS:
.layout {
display: grid;
min-height: 100dvh;
grid-template-columns:
minmax(12rem, 16rem)
minmax(0, 1fr)
minmax(12rem, 16rem);
grid-template-rows: auto 1fr auto;
grid-template-areas:
"cabecera cabecera cabecera"
"lateral contenido relacionado"
"pie pie pie";
gap: 1rem;
padding: clamp(1rem, 3vw, 2rem);
}
.cabecera {
grid-area: cabecera;
}
.lateral {
grid-area: lateral;
}
.contenido {
grid-area: contenido;
}
.relacionado {
grid-area: relacionado;
}
.pie {
grid-area: pie;
}
Cada línea entre comillas representa una fila y cada palabra, una columna. Por eso todas las filas de grid-template-areas deben tener el mismo número de celdas. Repetir un nombre hace que esa zona abarque varias columnas; un punto (.) deja una celda vacía.
Los nombres no tienen un significado reservado. Elegir términos que describan la función de cada zona hace que la distribución sea más fácil de mantener que una colección de coordenadas numéricas.
En una pantalla estrecha, las tres columnas anteriores dejarían muy poco espacio al contenido. No hace falta reconstruir el HTML: basta con redefinir la cuadrícula.
@media (max-width: 56.25rem) {
.layout {
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-template-areas:
"cabecera"
"lateral"
"contenido"
"relacionado"
"pie";
}
}
El punto de ruptura no debería elegirse porque corresponda a un modelo concreto de tablet. Reduce la ventana o usa el modo responsive del navegador y observa cuándo el contenido deja de respirar, se solapa o genera desplazamiento horizontal. Ahí está el punto en el que la composición pide un cambio.
Mantén, además, un orden lógico en el HTML. Grid puede mover visualmente los bloques, pero un lector de pantalla y la navegación por teclado siguen el orden del documento. Una cuadrícula atractiva no compensa una secuencia difícil de entender.
spanNo siempre necesitas áreas con nombre. Para hacer que una tarjeta destacada ocupe dos columnas, puedes indicar entre qué líneas se extiende:
.tarjeta-destacada {
grid-column: 1 / 3;
}
También puedes expresar la misma idea con span sin fijar la línea final:
.tarjeta-destacada {
grid-column: span 2;
}
Con span, la colocación suele ser más flexible cuando el navegador ordena los elementos automáticamente. También funciona en filas:
.tarjeta-alta {
grid-row: span 2;
}
Usa coordenadas cuando la posición forme parte de la estructura. Si buscas superponer un elemento, fijarlo al viewport o sacarlo del flujo, entonces estás resolviendo otro problema; conviene revisar cómo funciona position en CSS antes de mezclar ambos sistemas.
Grid distingue entre alinear el contenido de cada celda y alinear la cuadrícula completa dentro del contenedor.
.galeria {
display: grid;
place-items: center;
}
place-items combina align-items y justify-items. Con center, los elementos se centran en ambos ejes dentro de sus celdas. Si solo quieres cambiar una tarjeta, utiliza align-self, justify-self o su abreviatura place-self.
.tarjeta-especial {
place-self: end center;
}
Por otro lado, justify-content, align-content y place-content distribuyen la cuadrícula como conjunto cuando sus pistas ocupan menos que el contenedor. Confundir ambos grupos es una causa frecuente de que “no pase nada” al cambiar una propiedad.
Si tu objetivo concreto es alinear una caja en el centro, encontrarás una comparación de métodos en la guía para centrar un div con CSS.
Cuando hay más elementos que celdas declaradas, el algoritmo de colocación crea nuevas pistas. Puedes definir su tamaño con grid-auto-rows:
.listado {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(8rem, auto);
gap: 1rem;
}
Cada fila implícita medirá como mínimo 8rem, pero podrá crecer si el contenido lo necesita. Evita alturas rígidas cuando el texto pueda variar; de lo contrario, una descripción larga terminará desbordando su tarjeta.
grid-auto-flow controla la dirección de colocación automática. Su valor inicial es row, por lo que el navegador completa cada fila antes de pasar a la siguiente. El valor dense intenta rellenar huecos anteriores con elementos posteriores, pero puede alterar el orden visual respecto al HTML. Resérvalo para colecciones puramente visuales en las que esa diferencia no perjudique la lectura ni la interacción.
Elegir bien depende de cuántas dimensiones necesites coordinar, no de que un sistema sea mejor que el otro.
| Situación | Grid | Flexbox |
| Layout completo con cabecera, lateral y contenido | Recomendado | Posible, pero menos directo |
| Galería con filas y columnas alineadas | Recomendado | Puede perder la alineación entre filas |
| Menú horizontal | Posible | Recomendado |
| Grupo de botones de ancho variable | Posible | Recomendado |
| Tarjetas que cambian de número de columnas | Recomendado | Posible con flex-wrap |
| Alinear elementos dentro de una tarjeta | Posible | Suele ser más sencillo |
Una combinación habitual queda así:
.listado {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1.5rem;
}
.tarjeta {
display: flex;
flex-direction: column;
}
.tarjeta .acciones {
margin-top: auto;
display: flex;
gap: 0.75rem;
}
Grid organiza las tarjetas; Flexbox mantiene sus botones agrupados y pegados a la parte inferior aunque las descripciones tengan longitudes distintas.
Las columnas afectan a los hijos directos del contenedor. Si declaras display: grid en una tarjeta esperando ordenar sus tarjetas hermanas, no ocurrirá: la regla debe ir en el padre común.
repeat(4, 1fr) siempre intenta conservar cuatro columnas. Para una galería flexible, combina auto-fit con minmax() o cambia el número de columnas en los puntos donde el contenido lo necesite.
Una columna 1fr tiene en cuenta el tamaño mínimo intrínseco de su contenido. Si aparece scroll horizontal, prueba minmax(0, 1fr) y revisa también imágenes, tablas, palabras largas y bloques de código. Las imágenes deberían tener, como mínimo, max-width: 100% y height: auto.
gap y márgenes sin una razóngap ya resuelve el espacio regular entre elementos. Mantener además márgenes laterales en cada tarjeta puede duplicar la separación y complicar los bordes de la cuadrícula.
Colocar el contenido principal antes en pantalla pero después en el DOM crea una experiencia distinta para quienes navegan con teclado o lector de pantalla. Empieza por un HTML con sentido y utiliza Grid para presentarlo, no para corregir una estructura semántica deficiente.
Un punto de ruptura cambia la distribución, pero no corrige una imagen sin límites, un texto interminable o una tabla demasiado ancha. Antes de añadir más condiciones, identifica qué elemento provoca el desbordamiento.
Este CSS reúne las decisiones principales de la guía y puede servir como base para una página real:
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: system-ui, sans-serif;
background: #f4f5f7;
color: #172033;
}
.layout {
display: grid;
min-height: 100dvh;
grid-template-columns:
minmax(12rem, 16rem)
minmax(0, 1fr)
minmax(12rem, 16rem);
grid-template-areas:
"cabecera cabecera cabecera"
"lateral contenido relacionado"
"pie pie pie";
gap: 1rem;
padding: clamp(1rem, 3vw, 2rem);
}
.cabecera,
.lateral,
.contenido,
.relacionado,
.pie {
padding: 1.25rem;
border-radius: 0.75rem;
background: #ffffff;
}
.cabecera { grid-area: cabecera; }
.lateral { grid-area: lateral; }
.contenido { grid-area: contenido; }
.relacionado { grid-area: relacionado; }
.pie { grid-area: pie; }
.proyectos {
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(min(100%, 15rem), 1fr)
);
gap: 1rem;
}
@media (max-width: 56.25rem) {
.layout {
grid-template-columns: 1fr;
grid-template-areas:
"cabecera"
"lateral"
"contenido"
"relacionado"
"pie";
}
}
En el exterior, la estructura cambia de tres columnas a una mediante una media query porque existe una decisión de diseño clara: las zonas laterales ya no caben junto al contenido. La cuadrícula interior de proyectos, en cambio, se adapta por sí sola con auto-fit porque solo necesita añadir o quitar columnas según el espacio disponible.
Esa combinación suele producir un CSS más estable que llenar la hoja de estilos de puntos de ruptura. Deja que el navegador resuelva los cambios repetitivos y reserva las media queries para transformaciones reales de la composición.
Cuando la maquetación forma parte de un proyecto con requisitos propios (jerarquía de contenidos, conversión, accesibilidad y rendimiento), el siguiente paso es diseñar el sistema completo, no acumular reglas aisladas. En Overant podemos trasladar esa estructura a un proyecto de diseño web a medida adaptado al contenido y a los objetivos del negocio.

¿Qué te ha parecido este artículo?