Antes de CSS Grid, construir un diseño de página adecuado significaba floats, clearfixes, márgenes negativos y una plegaria para que las columnas no colapsaran. Flexbox ayudó, pero es fundamentalmente unidimensional — obtienes una fila o una columna, no ambas. CSS Grid es el primer sistema de diseño nativo de CSS realmente diseñado para diseños bidimensionales. El desafío no es el soporte del navegador — ha sido universal desde 2017. El desafío es que la API tiene mucha superficie y el nombrado es suficientemente inconsistente para ser confuso si no tienes el modelo subyacente claro. Este artículo se enfoca en las partes que usarás en el trabajo real.
Filas, columnas y el contenedor de cuadrícula
Todo comienza con display: grid en el contenedor. Una vez establecido, los hijos directos se convierten automáticamente en elementos de cuadrícula — no se necesita ninguna clase en ellos. Defines las pistas de columnas y filas con grid-template-columns y grid-template-rows.
La unidad clave a entender primero es fr — la unidad fraccionaria. Representa una fracción del espacio disponible en el contenedor de cuadrícula después de que se han considerado las pistas de tamaño fijo. Un 1fr significa "tomar una parte del espacio restante". Dos columnas de 1fr 1fr significa mitades iguales. 2fr 1fr significa que la primera columna obtiene el doble que la segunda. Esta es la unidad que hace que las cuadrículas fluidas se sientan naturales.
/* 3-column blog card layout */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto;
gap: 1.5rem;
}
/* repeat(3, 1fr) is shorthand for: 1fr 1fr 1fr */
/* auto rows size to their content */repeat(n, track) es una abreviatura para que no tengas que escribir el mismo tamaño de pista cinco veces. También funciona con valores mixtos: repeat(3, 1fr 2fr) te da una cuadrícula de 6 columnas alternando pistas estrechas y anchas. Para las filas, auto es casi siempre lo que quieres — las filas se dimensionan según su contenido a menos que necesites explícitamente una altura fija.
<div class="card-grid">
<article class="card">
<img src="/posts/grid-post-1.jpg" alt="CSS Grid post 1">
<h2>Getting Started with Grid</h2>
<p>A practical intro for developers moving from Flexbox.</p>
</article>
<article class="card">
<img src="/posts/grid-post-2.jpg" alt="CSS Grid post 2">
<h2>Grid vs Flexbox</h2>
<p>Which layout tool to reach for, and when.</p>
</article>
<article class="card">
<img src="/posts/grid-post-3.jpg" alt="CSS Grid post 3">
<h2>Responsive Grids Without Media Queries</h2>
<p>Using minmax() to handle reflow automatically.</p>
</article>
</div>La propiedad gap
Antes de Grid, agregar espaciado entre los hijos del diseño significaba márgenes — y los márgenes significaban recordar resetear el último hijo, lidiar con el colapso y agregar márgenes negativos en el contenedor para compensar. gap resuelve esto limpiamente. Agrega espacio solo entre las pistas, nunca en los bordes exteriores de la cuadrícula.
/* Uniform gap between all rows and columns */
.card-grid {
gap: 1.5rem;
}
/* Different row and column gaps */
.dashboard {
row-gap: 2rem;
column-gap: 1rem;
}
/* gap is shorthand: row-gap then column-gap */
.dashboard {
gap: 2rem 1rem;
}gap también funciona en Flexbox (reemplazó el antiguo alias grid-gap). Si ya estás usando Flexbox para un componente y solo necesitas espaciado entre elementos, puedes usar gap allí también sin cambiar a Grid.Colocación explícita de elementos
Por defecto, los elementos de cuadrícula fluyen hacia la siguiente celda disponible en el orden de origen. Pero el verdadero poder de Grid es que puedes colocar elementos en cualquier lugar — e incluso hacer que abarquen múltiples pistas. Las propiedades son grid-column y grid-row, que hacen referencia a las líneas de cuadrícula (las líneas entre las pistas, numeradas desde 1).
/* Dashboard where the first card spans 2 columns */
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}
.card--featured {
grid-column: 1 / 3; /* start at line 1, end at line 3 */
}
/* span keyword: simpler when you don't care about exact position */
.card--featured {
grid-column: span 2; /* occupy 2 column tracks from wherever it lands */
}
/* Spanning rows too */
.card--tall {
grid-row: span 2; /* occupy 2 row tracks */
}
/* Explicit positioning: place a panel in column 3-5, row 1-2 */
.sidebar {
grid-column: 3 / 5;
grid-row: 1 / 2;
}Los números de línea comienzan en 1 para el borde izquierdo/superior y van hasta n+1 donde n es el número de pistas. Los números de línea negativos cuentan desde la derecha/abajo: grid-column: 1 / -1 extiende un elemento por todo el ancho de la cuadrícula sin importar cuántas columnas haya — un truco útil para elementos de ancho completo dentro de un contenedor de múltiples columnas.
grid-template-areas — Nombra tu diseño
Esta es la función que hace que Grid sea genuinamente excelente para diseños a nivel de página, y es la API más legible de todo CSS. En lugar de colocar elementos por números de línea, dibujas el diseño como arte ASCII en el CSS, luego le dices a cada elemento qué área nombrada ocupa. La especificación de grid-template-areas requiere que cada fila tenga el mismo número de celdas, y cada área nombrada debe ser rectangular — sin formas en L.
/* Full page layout: header, sidebar, main, footer */
.page-shell {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: 60px 1fr 50px;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
gap: 0;
}
.page-header { grid-area: header; }
.page-sidebar { grid-area: sidebar; }
.page-main { grid-area: main; }
.page-footer { grid-area: footer; }<div class="page-shell">
<header class="page-header">Site header / nav</header>
<nav class="page-sidebar">Sidebar navigation</nav>
<main class="page-main">Primary content</main>
<footer class="page-footer">Footer</footer>
</div>Un punto (.) en la cadena de plantilla deja una celda intencionalmente vacía. También puedes apilar el mismo nombre en múltiples celdas para abarcarlas — eso es exactamente lo que hace "header header" arriba. Cuando redimensionas o reestructuras el diseño para diferentes puntos de vista, actualizas la cadena de plantilla en un solo lugar en lugar de buscar múltiples declaraciones grid-column.
auto-fill vs auto-fit con minmax()
El patrón detrás de las cuadrículas responsivas sin consultas de medios es uno de los trucos más prácticos de Grid: repeat(auto-fill, minmax(250px, 1fr)). Desglósalo — minmax(250px, 1fr) dice que cada columna debe tener al menos 250px de ancho pero puede expandirse para llenar el espacio disponible. auto-fill le dice a Grid que cree tantas columnas como quepan en el contenedor dada esa restricción. El resultado es una cuadrícula que automáticamente gana y pierde columnas a medida que cambia la ventana gráfica.
/* Product card grid — reflows automatically, no media queries */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 1.5rem;
}
/* auto-fit collapses empty tracks — items stretch to fill the container */
.product-grid--stretch {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1.5rem;
}La diferencia entre auto-fill y auto-fit es sutil pero importa cuando hay menos elementos que columnas. Con auto-fill, Grid reserva espacio para las pistas potenciales incluso si están vacías — los elementos permanecen en su ancho mínimo. Con auto-fit, las pistas vacías se colapsan a cero y los elementos se expanden para llenar la fila. Para cuadrículas de productos y galerías donde quieres que los elementos usen el espacio disponible, auto-fit generalmente se ve mejor. Para cuadrículas donde el ancho de elemento consistente importa más que llenar el contenedor, auto-fill es la elección correcta.
auto-fill y auto-fit con minmax() tienen un excelente soporte — 97%+ globalmente según caniuse. Puedes usar este patrón hoy sin un respaldo en cualquier proyecto moderno.Alineación en Grid
Grid usa el mismo módulo de Alineación de Caja que Flexbox, por lo que los nombres de las propiedades se corresponden directamente si ya conoces Flexbox. El modelo mental clave: justify opera en el eje inline (horizontal en la mayoría de los modos de escritura), align opera en el eje de bloque (vertical).
justify-items/align-items— alineación predeterminada para todos los elementos dentro de su celda de cuadrícula. El valor predeterminado esstretch, por eso los elementos de cuadrícula llenan su celda automáticamente.justify-content/align-content— distribuye las pistas mismas dentro del contenedor cuando la cuadrícula es más pequeña que el contenedor (similar aljustify-contentde Flexbox en el contenedor flex).justify-self/align-self— anula la alineación para un solo elemento. Útil cuando un elemento necesita estar centrado mientras otros se estiran.- Valores:
start,end,center,stretch,space-between,space-around,space-evenly(los tres últimos solo para*-content).
/* Center all card content within its cell */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
align-items: start; /* cards align to their cell top, not stretched */
gap: 1.5rem;
}
/* Center a single call-to-action card both ways */
.card--cta {
justify-self: center;
align-self: center;
}
/* Distribute tracks with space between — useful for nav bars */
.nav-grid {
display: grid;
grid-template-columns: auto auto auto;
justify-content: space-between;
}Si vienes de Flexbox, la diferencia principal es que la alineación de Grid opera en un espacio bidimensional — puedes controlar ambos ejes simultáneamente. En Flexbox, la alineación en el eje transversal se aplica a toda una fila o columna de elementos; en Grid, cada elemento tiene su propia celda, por lo que justify-self y align-self te dan control por elemento sin necesitar elementos envolventes.
Diseño real: estructura completa de panel de control
Aquí hay una estructura de página CSS Grid completa para una aplicación de panel de control — encabezado, barra lateral de navegación colapsable, área de contenido principal con su propia cuadrícula interna y pie de página. Este es el patrón que usarías como la capa de diseño más externa para un panel SaaS o panel de administración.
/* ── Dashboard shell ──────────────────────────────────── */
.dashboard-shell {
display: grid;
grid-template-columns: 220px 1fr;
grid-template-rows: 56px 1fr 44px;
grid-template-areas:
"topbar topbar"
"sidenav content"
"sidenav footer";
min-height: 100vh;
}
.dashboard-topbar { grid-area: topbar; background: #1e293b; }
.dashboard-sidenav { grid-area: sidenav; background: #0f172a; overflow-y: auto; }
.dashboard-content { grid-area: content; padding: 1.5rem; overflow-y: auto; }
.dashboard-footer { grid-area: footer; background: #f8fafc; border-top: 1px solid #e2e8f0; }
/* ── Collapsed sidebar variant ────────────────────────── */
.dashboard-shell--collapsed {
grid-template-columns: 56px 1fr;
}
/* ── Content area — internal card grid ─────────────────── */
.dashboard-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
grid-template-rows: auto;
align-content: start;
gap: 1.25rem;
}
/* Stat cards take one column each; the main chart spans all */
.stat-card { /* auto-placed, one column */ }
.main-chart { grid-column: 1 / -1; } /* always full width */
/* ── Responsive: collapse to single-column on small screens */
@media (max-width: 768px) {
.dashboard-shell {
grid-template-columns: 1fr;
grid-template-rows: 56px 1fr auto 44px;
grid-template-areas:
"topbar"
"content"
"sidenav"
"footer";
}
}<div class="dashboard-shell">
<header class="dashboard-topbar">
<a href="/dashboard" class="brand">AppName</a>
<nav class="topbar-actions">
<button class="btn-icon" aria-label="Notifications">
<span class="icon-bell"></span>
</button>
<img src="/avatar/user.png" class="user-avatar" alt="User menu">
</nav>
</header>
<nav class="dashboard-sidenav">
<ul>
<li><a href="/dashboard">Overview</a></li>
<li><a href="/dashboard/analytics">Analytics</a></li>
<li><a href="/dashboard/users">Users</a></li>
<li><a href="/dashboard/settings">Settings</a></li>
</ul>
</nav>
<main class="dashboard-content">
<div class="stat-card">Monthly Revenue</div>
<div class="stat-card">Active Users</div>
<div class="stat-card">Churn Rate</div>
<div class="main-chart">Revenue Chart (full width)</div>
</main>
<footer class="dashboard-footer">
<p>AppName v2.4.1 — <a href="/status">System Status</a></p>
</footer>
</div>Algunas cosas que vale la pena notar en este ejemplo. El pie de página se coloca en la columna sidenav en pantallas grandes usando la definición del área de plantilla, lo que lo mantiene visualmente separado del área de desplazamiento del contenido principal. El 1fr en las filas y overflow-y: auto en el panel de contenido significa que el área de contenido se desplaza de forma independiente — la barra superior y la sidenav permanecen fijas, que es la UX estándar del panel. La consulta @media en la parte inferior reordena las áreas de cuadrícula para móvil sin tocar el HTML en absoluto.
Conclusión
La curva de aprendizaje de CSS Grid proviene principalmente del nombrado — líneas, pistas, áreas, unidades fr — pero una vez que el modelo hace clic, es notablemente directo. Para diseños reales: usa grid-template-areas para las estructuras de página (se lee como un wireframe), usa repeat(auto-fit, minmax()) para cuadrículas de tarjetas responsivas, y usa grid-column: span N explícito para elementos que rompen el flujo estándar. No necesitas toda la API de Grid para el 90% del trabajo real — estos patrones cubren la mayor parte.
Para más lectura: la Guía Completa de CSS-Tricks para Grid es la mejor referencia de una sola página; la documentación CSS Grid de MDN profundiza en cada propiedad; y la especificación CSS Grid Level 1 del W3C es sorprendentemente legible si quieres entender el comportamiento exacto de los casos límite. La compatibilidad del navegador es excelente — consulta caniuse.com/css-grid para los números actuales. Si estás trabajando en un proyecto en vivo y quieres limpiar tu CSS, el formateador de CSS en este sitio ordenará y embellecerá tus hojas de estilo.