
Si alguna vez has construido un grid de tarjetas donde los títulos, extractos y enlaces "Leer más" se niegan tercamente a alinearse, ya conoces el dolor que pueden causar los grids anidados. Ajustas min-height, duplicas definiciones de tracks, abusas de display: contents, y todo sigue sintiéndose frágil.
CSS subgrid es la característica que finalmente soluciona esa clase de problemas de layout. Permite que los grids anidados reutilicen las tracks y nombres de líneas exactos de su padre, de modo que los componentes se alineen como si estuvieran dispuestos en el mismo grid — incluso cuando están varios niveles de profundidad.
Un video reciente sobre "CSS Subgrid para alineación perfecta" muestra cómo subgrid resuelve esas molestas inconsistencias en diseños modernos. En este artículo iremos más allá: desglosaremos cómo funciona subgrid, dónde brilla, dónde duele, y cómo integrarlo en una base de código moderna TypeScript/React y un sistema de diseño.
Tabla de Contenidos
- Qué es Realmente CSS Subgrid
- Cómo se Compara Subgrid con Grids Anidados y display: contents
- Sintaxis de Subgrid en la Práctica
- Un Ejemplo Realista: Grid de Tarjetas Alineadas con React + TypeScript
- Subgrid a Escala de Página: Macro Grids y Sistemas de Diseño
- Pros y Contras de Usar Subgrid Hoy
- Soporte de Navegadores y Mejora Progresiva
- Cuándo Deberías Usar Subgrid (y Cuándo No)
- Recursos y Repositorios Recomendados
- Resumen
- Referencias
Qué es Realmente CSS Subgrid
CSS Grid Level 1 nos dio layout bidimensional con filas y columnas, pero los grids anidados siempre fueron independientes. Un grid hijo no podía "ver" los tamaños de tracks o nombres de líneas de su padre. Alinear contenido anidado significaba copiar definiciones de tracks y esperar que nada se desincronizara.
Subgrid es un valor para grid-template-columns y grid-template-rows:
.subgrid {
display: grid;
grid-template-columns: subgrid;
/* o */
grid-template-rows: subgrid;
/* o ambos mediante shorthand */
grid: subgrid / subgrid;
}
En lugar de definir sus propios tracks, un subgrid usa los tracks del área que abarca en su grid padre. Eso incluye:
- Tamaños de tracks (
1fr,minmax,auto, etc.). - Gaps entre tracks.
- Líneas de grid con nombre (y puedes agregar más nombres localmente).
En otras palabras, si un subgrid abarca tres column tracks del padre, tendrá tres column tracks de exactamente el mismo tamaño. Los hijos del subgrid pueden entonces alinearse a esos tracks como si fueran hijos directos del grid padre.
Cómo se Compara Subgrid con Grids Anidados y display: contents
Antes de subgrid, la gente probó varias estrategias imperfectas.
Grids anidados sin subgrid
Defines un grid padre, luego dentro de cada tarjeta (o componente) defines otro grid:
.cards {
display: grid;
grid-template-columns: repeat(3, minmax(16rem, 1fr));
gap: 1.5rem;
}
.card {
display: grid;
grid-template-rows: auto 1fr auto; /* duplicado */
}
Cada grid anidado es independiente, por lo que la alineación de header/body/footer entre tarjetas es casual. Cualquier cambio al grid padre debe reflejarse manualmente en los grids hijos. MDN explícitamente señala esto como una limitación central que subgrid resuelve.
Trucos con display: contents
Un workaround común es usar display: contents en wrappers, para que los nietos se conviertan en items de grid directos y puedan alinearse al grid de nivel superior. Esto tiene problemas:
- Rompe la semántica para algunos casos de uso (p. ej., wrappers
<article>,<section>desapareciendo del layout pero no del DOM). - Puede confundir herramientas de accesibilidad y devtools del navegador.
- No ayuda cuando sí quieres que el wrapper sea un límite de layout (p. ej., una tarjeta con grid interno).
Subgrid en cambio mantiene el wrapper como un item de grid real, pero permite que su grid interno reutilice los tracks del padre.
Por qué importa a los expertos
Grid Level 2, y especialmente subgrid, existen precisamente para solucionar estas limitaciones de alineación anidada y hacer que alinear items de grid anidados con el grid principal sea directo.
— Rachel AndrewLa diseñadora front-end Chen Hui Jing llama al trabajo de Andrew sobre Grid "uno de los mejores recursos que encontrarás" si quieres entender completamente esta herramienta de layout. Subgrid es una parte central de esa historia.
Sintaxis de Subgrid en la Práctica
A nivel de propiedad, subgrid es simple:
grid-template-columns: subgrid;grid-template-rows: subgrid;- O
grid: subgrid / subgrid;para ambos ejes.
Un ejemplo mínimo basado en los patrones de MDN:
<div class="grid">
<div class="feature">
<div class="feature-inner">
<!-- Contenido anidado aquí -->
</div>
</div>
</div>
.grid {
display: grid;
grid-template-columns: repeat(9, 1fr);
grid-template-rows: repeat(4, minmax(100px, auto));
}
/* Este elemento es un *item* de grid y un *contenedor* de grid */
.feature {
display: grid;
grid-column: 2 / 7;
grid-row: 2 / 4;
grid-template-columns: subgrid; /* hereda 5 tracks del padre */
grid-template-rows: subgrid; /* hereda row tracks del padre */
}
.feature-inner {
/* Puede posicionarse usando números de línea o nombres definidos en el padre */
grid-column: 3 / 5; /* relativo a la propia línea 1..n del subgrid */
grid-row: 1 / 3;
}
El subgrid adopta los tracks del área que abarca (2 / 7, 2 / 4). Dentro de .feature, la numeración de líneas reinicia desde 1, pero los tamaños coinciden con el padre.
Un Ejemplo Realista: Grid de Tarjetas Alineadas con React + TypeScript
Construyamos un layout simple de tarjetas donde títulos, cuerpos y pies de página se alinean perfectamente entre tarjetas, independientemente de la longitud del texto.
El patrón es el mismo usado en varios artículos modernos sobre subgrid: el contenedor define tres row tracks (auto 1fr auto), y cada tarjeta usa un row subgrid para reutilizar esos tracks mientras abarca las tres filas. La fila "1fr" crece basándose en el cuerpo de tarjeta más alto.
Componente React + TypeScript
// components/ArticleGrid.tsx
import React from "react";
import styles from "./ArticleGrid.module.css";
type Article = {
id: number;
title: string;
excerpt: string;
meta: string;
};
const articles: Article[] = [
{
id: 1,
title: "Subgrid for perfectly aligned cards",
excerpt:
"Use CSS subgrid to keep titles, excerpts, and CTAs aligned across cards without duplicating track definitions.",
meta: "5 min read · Layout"
},
{
id: 2,
title: "Design systems and macro grids",
excerpt:
"Define a page-level grid once and let every component automatically snap to the same vertical rhythm.",
meta: "7 min read · Design Systems"
},
{
id: 3,
title: "Progressive enhancement with subgrid",
excerpt:
"Ship clean layouts to modern browsers while keeping older ones usable with a regular nested grid fallback.",
meta: "4 min read · CSS"
}
];
export const ArticleGrid: React.FC = () => {
return (
<section className={styles.section}>
<h1 className={styles.heading}>Latest articles</h1>
<div className={styles.grid}>
{articles.map((article) => (
<article key={article.id} className={styles.card}>
<h2 className={styles.cardTitle}>{article.title}</h2>
<p className={styles.cardExcerpt}>{article.excerpt}</p>
<footer className={styles.cardMeta}>{article.meta}</footer>
</article>
))}
</div>
</section>
);
};
Esto es React + TypeScript estándar: los datos están tipados, el componente es autocontenido y utilizable inmediatamente en un proyecto Next.js o CRA.
Módulo CSS usando grid-template-rows: subgrid
/* components/ArticleGrid.module.css */
.section {
padding: 2rem clamp(1.5rem, 4vw, 4rem);
background: #020617; /* casi negro */
color: #e5e7eb; /* gray-200 */
}
.heading {
font-size: clamp(1.5rem, 3vw, 2rem);
margin-bottom: 1.5rem;
}
/* Grid padre: columnas + filas compartidas para header/body/footer */
.grid {
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(18rem, 1fr)
);
/* Tres filas: título, cuerpo flexible, pie */
grid-template-rows: auto 1fr auto;
gap: 1.5rem;
}
/* Cada tarjeta se convierte en un subgrid para filas */
.card {
display: grid;
grid-template-rows: subgrid; /* reutiliza auto 1fr auto */
grid-row: auto / span 3; /* abarca las tres filas padre */
padding: 1.25rem 1.5rem;
border-radius: 0.75rem;
background: #020617;
border: 1px solid #1f2933;
box-shadow: 0 18px 45px rgba(15, 23, 42, 0.6);
}
/* Los hijos se alinean a las row tracks compartidas */
.cardTitle {
grid-row: 1;
font-size: 1.125rem;
font-weight: 600;
margin: 0 0 0.5rem;
}
.cardExcerpt {
grid-row: 2;
margin: 0 0 0.75rem;
font-size: 0.95rem;
line-height: 1.5;
}
.cardMeta {
grid-row: 3;
margin-top: auto;
font-size: 0.85rem;
opacity: 0.75;
}
Qué está pasando aquí:
- El contenedor
.griddefine tres row tracks:auto 1fr auto. La fila del medio es flexible y crece para ajustarse al cuerpo de tarjeta más alto. - Cada
.carddeclaragrid-template-rows: subgridy abarca tres filas (grid-row: auto / span 3). Esto le dice a la tarjeta que reutilice esos tres tracks para su propio layout interno. - El
h2,p, yfooterse asignan a las filas1,2, y3. Como cada tarjeta comparte las mismas filas de subgrid, los títulos y pies se alinean perfectamente en fila a través de todo el grid.
Este es exactamente el tipo de layout que el video y muchos posts de blog usan para mostrar por qué subgrid se siente como un avance comparado con grids anidados puros.
Subgrid a Escala de Página: Macro Grids y Sistemas de Diseño
Uno de los patrones más poderosos descritos en el artículo oficial de web.dev es la idea de un macro grid: un grid que cubre toda la página (o viewport del dispositivo), con filas y columnas con nombre para cosas como barra de estado, nav, header, main y footer. Las regiones anidadas luego se suscriben a ese grid vía subgrid, pasando nombres y tamaños de tracks hacia abajo en el árbol.
Una versión simplificada de esa idea:
/* Macro grid de dispositivo/página */
.device {
display: grid;
grid-template-rows:
[status] 3.5rem
[nav] 3rem
[header] 4rem
[main] auto
[footer] 4rem;
grid-template-columns:
[fullbleed-start] 1rem
[content-start] auto
[content-end] 1rem
[fullbleed-end];
}
/* El contenedor de la app y todos sus hijos directos comparten los mismos tracks */
.device > .app,
.app > * {
display: grid;
grid: subgrid / subgrid; /* filas y columnas de .device */
}
Ahora cualquier componente renderizado dentro de .app puede alinearse a las mismas líneas con nombre ([header], [main], [footer], [content-start], etc.) incluso si está varios niveles de profundidad. Esto es extremadamente valioso en sistemas de diseño, donde quieres:
- Ritmo vertical consistente a través de micro-frontends independientes.
- Colocación predecible de secciones de ancho completo (hero, banners, franjas promocionales).
- Modelo mental compartido entre diseñadores (grid de Figma) e ingenieros (CSS grid).
Pros y Contras de Usar Subgrid Hoy
Ventajas
1. Alineación real para layouts anidados
Subgrid alinea componentes anidados a los mismos tracks que sus padres, sin duplicar reglas de tamaño. Esto es ideal para grids de tarjetas, dashboards complejos y layouts editoriales con anidamiento profundo.
2. CSS más limpio y mantenible
En lugar de repetir grid-template-rows o grid-template-columns en cada componente anidado, defines tracks una vez y dejas que los subgrids los reutilicen. Esto reduce la deriva y hace los refactors más seguros.
3. Mejor mapeo de diseño a código
Los diseñadores a menudo trabajan con un grid compartido dibujado sobre una página completa. Subgrid te permite implementar eso casi literalmente: un macro grid más subgrids anidados que pasan nombres de líneas hacia abajo.
4. Funciona por eje
Puedes hacer subgrid solo en filas, solo en columnas, o en ambos ejes. Esto es útil cuando, por ejemplo, quieres alineación vertical consistente pero necesitas más libertad horizontalmente (o viceversa).
Desventajas y advertencias
1. Los navegadores antiguos aún carecen de soporte
Las versiones modernas de Chrome (117+), Edge (117+), Firefox (71+), y Safari (16+) soportan subgrid. Pero navegadores antiguos, navegadores móviles legacy, e IE no lo hacen.
Aún debes proporcionar fallbacks, especialmente para sitios públicos con audiencias amplias.
2. El debugging se vuelve más conceptual
Cuando los subgrids comparten tracks y nombres de líneas, es fácil olvidar qué grid "posee" qué línea. Las DevTools modernas ayudan, pero el debugging requiere una comprensión sólida de la semántica de Grid y subgrid.
3. Rendimiento con layouts muy anidados
Subgrid en sí no es inherentemente lento, pero el anidamiento muy profundo de grids (con o sin subgrid) puede estresar algunos motores. Ha habido problemas de rendimiento documentados en layouts de grid anidados complejos en algunas versiones de Safari.
4. La lógica de fallback es sutil
Como subgrid es un valor válido incluso cuando no hay grid padre, algunos fallbacks en cascada no se comportan tan intuitivamente como los autores esperan. El CSS Working Group tiene discusiones activas alrededor de esto.
Soporte de Navegadores y Mejora Progresiva
A finales de 2025, el panorama finalmente es bueno:
- Firefox: soporte completo desde la versión 71 en adelante.
- Chrome / Edge: soporte en estable desde alrededor de 117/118; builds anteriores lo tenían detrás de flags o deshabilitado.
- Safari (macOS & iOS): soporte desde Safari 16.0, incluyendo Safari móvil.
MDN marca subgrid como Baseline: newly available since September 2023, lo que significa que se considera disponible en las versiones actuales de los motores principales, pero no en todos los dispositivos antiguos.
Fallback solo CSS con @supports
Para "nuevo layout, navegador antiguo aún usable", el patrón clásico de mejora progresiva es:
/* Baseline: grid anidado regular o flexbox */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
gap: 1.5rem;
}
.card {
display: grid;
grid-template-rows: auto 1fr auto; /* tracks duplicados */
}
/* Mejora: solo en navegadores que entienden subgrid */
@supports (grid-template-rows: subgrid) {
.cards {
grid-template-rows: auto 1fr auto;
}
.card {
grid-template-rows: subgrid;
grid-row: auto / span 3;
}
}
Los navegadores sin subgrid ignoran el bloque @supports y renderizan un grid anidado normal; los navegadores modernos mejoran a la alineación de subgrid. Este patrón coincide con lo que muchas guías prácticas recomiendan.
Helper TypeScript para detección de características
Si quieres mejora impulsada por JS (p. ej., para alternar una clase específica o cargar una hoja de estilos optimizada para subgrid), puedes usar CSS.supports en una pequeña utilidad TypeScript:
// utils/subgridSupport.ts
export function supportsSubgrid(): boolean {
if (typeof CSS === "undefined" || typeof CSS.supports !== "function") {
return false;
}
// Prueba filas o columnas; ambos están bien.
return CSS.supports("grid-template-rows", "subgrid");
}
Úsalo en un componente React:
import React from "react";
import { supportsSubgrid } from "../utils/subgridSupport";
import styles from "./ArticleGrid.module.css";
const hasSubgrid = supportsSubgrid();
export const ArticleGrid: React.FC = () => {
return (
<section
className={
hasSubgrid ? styles.sectionHasSubgrid : styles.sectionNoSubgrid
}
>
{/* ...mismo JSX que antes... */}
</section>
);
};
Luego en CSS, puedes definir variantes separadas:
.sectionNoSubgrid .card {
display: grid;
grid-template-rows: auto 1fr auto;
}
.sectionHasSubgrid .grid {
grid-template-rows: auto 1fr auto;
}
.sectionHasSubgrid .card {
display: grid;
grid-template-rows: subgrid;
grid-row: auto / span 3;
}
Esto refleja lo que el CSS Working Group y las discusiones de la comunidad sugieren: usa detección de características para controlar mejora progresiva, no para emular subgrid donde no existe.
Cuándo Deberías Usar Subgrid (y Cuándo No)
Usa subgrid cuando:
- Tienes componentes repetitivos (tarjetas, tiles, resúmenes de artículos) que deben alinearse en ritmos tanto verticales como horizontales a través de un grid padre.
- Mantienes un sistema de diseño con un grid de layout compartido y quieres que componentes independientes se ajusten a ese grid sin filtrar detalles de layout en cada componente.
- Tienes páginas editoriales o de dashboard complejas donde las secciones anidadas aún necesitan respetar un sistema de columnas o filas global.
- Estás principalmente apuntando a navegadores modernos, y los antiguos solo necesitan layout "suficientemente bueno" en lugar de alineación pixel-perfecta.
Evita o retrasa subgrid cuando:
- Tu audiencia incluye una porción significativa de navegadores legacy (webviews antiguos de Android, IE/Edge Legacy corporativo, dispositivos kiosco), y la alineación es más importante que la mantenibilidad.
- El layout es lo suficientemente simple como para que Grid estándar o Flexbox hagan el trabajo sin repetición o hacks.
- Aún no has estandarizado tu sistema de grid. Introducir subgrid sin una estrategia clara de macro grid y nombres puede hacer los layouts más confusos, no menos.
Un plan de migración razonable es:
- Define un macro grid y convención de nombres (
[content-start],[content-end], etc.). - Convierte uno o dos componentes de alto valor (p. ej., grid de tarjetas, shell de layout principal) a subgrid con fallbacks.
- Recopila feedback de diseñadores y desarrolladores.
- Implementa incrementalmente a través del sistema de diseño a medida que crece la confianza.
Recursos y Repositorios Recomendados
Si quieres seguir explorando subgrid, estos son referencias confiables y actualizadas:
-
MDN – Guía de Subgrid (detalles de especificación, ejemplos, compatibilidad)
https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout/Subgrid
-
web.dev – CSS subgrid (patrones de macro grid, ejemplos orientados a diseño)
-
Rachel Andrew – Grid Level 2 y Subgrid / libro "Get Ready for CSS Grid Layout"
Artículo y libro que profundizan en Grid Level 2 y subgrid desde la perspectiva de la autora de la especificación.
-
GitHub – Ejemplo CSS Subgrid (layout de tarjetas)
https://github.com/ditdot-dev/css-subgrid-example – proyecto de ejemplo HTML/CSS estático para layout estilo tarjeta con subgrid.
-
GitHub – Demo Next.js + CSS Modules subgrid
https://github.com/saltycrane/css-subgrid-example – un proyecto Next.js usando CSS Modules para demostrar subgrid en un stack React real.
-
Resumen de Subgrid e información baseline
- Can I Use – tabla de características: https://caniuse.com/css-subgrid
- Desglose de compatibilidad de navegadores: https://www.lambdatest.com/web-technologies/css-subgrid
Resumen
CSS subgrid no es "solo otro truco de layout"; es el eslabón perdido entre la forma en que los diseñadores piensan sobre grids y la forma en que los desarrolladores los implementan. Permite que los componentes anidados reutilicen los mismos tamaños y nombres de tracks que sus padres, dándote alineación real sin CSS duplicado o hacks frágiles.
Ahora tenemos soporte sólido de navegadores a través de los motores modernos. Con el uso cuidadoso de @supports, pequeños helpers de TypeScript, y una estrategia clara de grid en tu sistema de diseño, puedes comenzar a usar subgrid hoy — y retirar toda una clase de workarounds de layout.
Referencias
- MDN Web Docs - Subgrid
- YouTube - Learn CSS Subgrid for Perfect Alignment
- A Book Apart - Get Ready for CSS Grid Layout
- q2bstudio.com - Subgrid CSS: Control de diseño de siguiente nivel
- Stack Overflow - CSS grid-template-rows: subgrid
- DITDOT - CSS Subgrid - How to Build Complex Layouts
- web.dev - CSS subgrid
- FreeCodeCamp - What is CSS Subgrid?
- Can I Use - CSS Subgrid
- GitHub - Nested grid performance in Safari
- GitHub - CSS Working Group Drafts - conditional subgrid fallback
- Apple Developer - Safari 16 Release Notes
- Smashing Magazine - CSS Grid Level 2: Here Comes Subgrid
- GitHub - ditdot-dev/css-subgrid-example
- SaltyCrane Blog - CSS Subgrid demo
- LambdaTest - Browser Compatibility Score of CSS Subgrid