Subgrid: Heredando la cuadrícula matemática de los padres a los hijos.
📚 Contenido de la guía ⌃
- ¿Qué vamos a resolver hoy?
- El problema que sí duele: Tarjetas desalineadas
- Qué es CSS Subgrid (sin tecnicismos aburridos)
- Por qué Subgrid era la pieza que faltaba en CSS
- La sintaxis: Cómo heredar la retícula paso a paso
- Más allá de las medidas: Heredando la estructura lógica
- El caso de uso estrella: Tarjetas con anatomía perfecta
- Más allá de las tarjetas: Dashboards y Layouts Editoriales
- Criterio de Arquitecto: Cuándo NO usar Subgrid
- Compatibilidad actual y estrategia de Fallback
- Errores comunes al implementar Subgrid
- Conclusión: La matemática sigue viva
- Checklist rápido: ¿Debería usar Subgrid aquí?
CSS Subgrid: Heredando la Matemática
Tus tarjetas pueden tener grids internos, pero sus títulos, precios o botones casi nunca quedan alineados entre sí. Hoy en Tu Código Cotidiano vamos a resolver esta fractura visual. Entenderemos por qué Subgrid existe: para que los hijos hereden la lógica matemática del padre y se alineen de verdad.
¿Qué vamos a resolver hoy?
Evitaremos que esta guía sea una simple lista aburrida de propiedades CSS abstractas. Vamos a abordar un dolor muy real en el desarrollo de interfaces. Si alineas un listado de componentes y te das cuenta de que el botón de la tarjeta A no se alinea con el botón de la tarjeta B porque los textos tienen distinto tamaño, estás sufriendo la "fractura de los grids anidados".
Al final del artículo, sabrás cómo usar subgrid para que los hijos hereden el layout base, logrando alineaciones perfectas sin usar "márgenes mágicos" ni alturas fijas.
Desarrollador Web o Diseñador UI que ya sabe usar CSS Grid para armar estructuras básicas, pero sufre creando layouts consistentes a múltiples niveles.
Crear display: grid dentro de otro grid genera un "universo de bolsillo". La lógica del padre no penetra en el hijo, fracturando el diseño del sistema.
El problema que sí duele: Tarjetas desalineadas
Piensa en el patrón de diseño más común de la web: un listado de tarjetas (servicios, productos, artículos). Tú aplicas un display: grid en el contenedor principal para ordenar las tarjetas en columnas. Hasta ahí, todo es perfecto.
Pero luego, cada tarjeta necesita su propia cuadrícula interna para acomodar su imagen, título, precio y botón de acción. Como señala la documentación oficial (MDN y web.dev), las pistas de un grid padre solo sirven para posicionar a los hijos directos. Al declarar un nuevo grid dentro de la tarjeta, la estructura matemática del layout general se pierde por completo.
Aquí es donde nace la fractura: un título ligeramente más largo en una tarjeta empuja el precio hacia abajo, desalineándolo de la tarjeta vecina. Tu interfaz pierde el ritmo visual y empieza a verse descuidada, porque las piezas internas ya no comparten la misma lógica espacial.
Lo más frustrante de este problema es que tu código CSS no tiene errores de sintaxis. Si inspeccionas este comportamiento, verás el patrón clásico del grid anidado que todos hemos escrito mil veces:
card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.card {
display: grid;
<span style="color: #ea580c; font-weight: bold;">grid-template-rows: auto auto 1fr auto;</span> <span style="color: #64748b; font-style: italic;">/* Título, Meta, Info, Botón */</span>
gap: 1rem;
}
En el ejemplo anterior, la propiedad grid-template-rows dentro de .card calcula el espacio basándose únicamente en el contenido de esa tarjeta específica, ignorando por completo lo que miden los títulos de sus hermanas. Para solucionar esto, no necesitamos trucos con JavaScript ni asignar alturas fijas en píxeles; necesitamos heredar la cuadrícula del padre.
El grid anidado clásico aísla la estructura. La función subgrid permite que un grid interno comparta las medidas de las pistas (tracks), las plantillas y los nombres de línea con su ancestro, fusionando los componentes en un solo sistema matemático.
Qué es CSS Subgrid (sin tecnicismos aburridos)
Para entender subgrid, primero hay que entender lo que no es: no es una nueva propiedad mágica de CSS, ni es un valor de display (no escribes display: subgrid).
subgrid es simplemente un valor que le puedes pasar a las propiedades que ya conoces: grid-template-columns y grid-template-rows.
Cuando a un elemento hijo (que ya es display: grid) le pones el valor subgrid en sus columnas o filas, le estás dando una instrucción muy clara al navegador: "Oye, no inventes nuevas pistas matemáticas para mí. Mírate en el espejo de tu padre y adopta exactamente la porción del grid principal sobre la que estoy sentado".
Fíjate bien en la imagen superior. El módulo hijo azul oscuro no está definiendo que sus columnas miden "100px" ni "1fr". Simplemente se acopla a la retícula global que existe en el fondo. Si mañana cambias el tamaño de las columnas en el contenedor principal superior (el padre), este hijo se actualizará y ajustará automáticamente.
Esta es la magia de adoptar la "porción del padre". Rompe el aislamiento. Ahora puedes tener componentes muy complejos, anidados unos dentro de otros a varios niveles de profundidad, y todos pueden responder a una única fuente de verdad matemática definida en la etiqueta <main> o <body> de tu aplicación web.
Lo fascinante de subgrid es que puedes decidir qué heredar. Puedes heredar solo las columnas (para que los anchos coincidan perfectamente con tus hermanas), pero declarar tus propias filas autónomas. O viceversa. O ambas. Tú tienes el control.
Por qué Subgrid era la pieza que faltaba en CSS
Antes de que existiera subgrid, teníamos un problema grave de "amnesia espacial" en el navegador. Imagina que defines una cuadrícula maestra de 12 columnas para tu página. Colocas un artículo que ocupa desde la columna 2 hasta la 8. Perfecto.
Pero, ¿qué pasaba si querías que los elementos dentro de ese artículo se alinearan con las columnas 3, 4 y 5 de la página principal? No podías. Al anidar un nuevo display: grid, el contenedor hijo "olvidaba" por completo las líneas, los tamaños de las pistas (tracks) y los nombres de línea de su padre.
Los desarrolladores teníamos que recurrir a trucos: usar porcentajes, adivinar anchos fijos o usar variables CSS complejas para intentar imitar la cuadrícula exterior. Y todo ese castillo de naipes se derrumbaba en el momento en que el contenido dinámico (un texto más largo o una imagen de otro tamaño) entraba en juego.
Como puedes ver en la comparativa, subgrid existe por una razón de peso: es la única forma nativa en CSS de mantener la integridad estructural en layouts anidados sin tener que duplicar valores ni pelear con anchos en porcentajes.
Al compartir los tamaños de los tracks (las pistas por donde fluye el contenido), una tarjeta anidada ya no tiene que preocuparse por medir el ancho de sus columnas; simplemente le dice al navegador: "Hazme coincidir con las columnas de mi contenedor principal".
Basta de teoría. Veamos cómo se escribe esto en el mundo real.
La sintaxis: Cómo heredar la retícula paso a paso
Implementar esta técnica es sorprendentemente sencillo. Lo primero que debes recordar es que el elemento hijo sigue necesitando ser un grid. No puedes usar subgrid en un bloque normal; primero debes declararlo con display: grid.
Una vez que el hijo es un grid, en lugar de inventar tamaños para tus columnas o filas (como harías con 1fr 1fr o 200px auto), simplemente usas la palabra clave subgrid.
La genialidad de esta sintaxis es que es direccional. Puedes heredar solo las columnas, solo las filas, o ambas dimensiones al mismo tiempo, dependiendo de lo que necesite tu diseño.
Pasar esta lógica visual al código es directo y limpio. Tienes tres opciones principales dependiendo de tu objetivo de diseño:
/* ESCENARIO 1: Heredar SOLO columnas */
/* Útil cuando quieres que las tarjetas midan lo mismo de ancho, pero definan sus propias alturas internas */
.hijo-columnas {
display: grid;
grid-template-columns: subgrid;
grid-template-rows: auto 1fr auto; /* Filas locales */
}
/* ESCENARIO 2: Heredar SOLO filas */
/* Útil para listas o tablas donde franjas horizontales deben cruzarse de lado a lado */
.hijo-filas {
display: grid;
grid-template-columns: 1fr 2fr; /* Columnas locales */
grid-template-rows: subgrid;
}
/* ESCENARIO 3: Heredar TODO el layout */
/* Fusión total con la matemática del contenedor padre */
.hijo-absoluto {
display: grid;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
}
Cuando usas subgrid, tu elemento hijo hereda automáticamente el gap del padre para mantener la geometría perfecta. Sin embargo, si lo necesitas, puedes sobreescribir ese espaciado declarando un nuevo gap, row-gap o column-gap dentro del hijo.
Más allá de las medidas: Heredando la estructura lógica
Hasta ahora hemos hablado de heredar anchos (como 200px o 1fr), pero la verdadera potencia de subgrid para construir arquitecturas sólidas va un paso más allá: también hereda los nombres de las líneas del grid padre.
Si eres de los que nombran las líneas en CSS Grid (por ejemplo, [content-start] o [sidebar-end]), sabes lo útil que es para posicionar elementos sin tener que contar columnas matemáticamente. Cuando un componente hijo declara subgrid, todas esas líneas nombradas por el padre "atraviesan" la frontera del hijo y quedan disponibles para ser usadas internamente.
Esto significa que puedes tener un componente anidado a tres niveles de profundidad que, internamente, posiciona un elemento diciéndole: "Alineate con la línea [content-start] del layout maestro", y funcionará a la perfección.
Mira este escenario sumamente común en arquitecturas modernas: tienes un contenedor principal (layout) que define nombres para organizar el contenido centrado y los sangrados (bleed) laterales. Si insertas un componente de ancho completo, puedes hacer que sus hijos internos respeten ese contenido centrado heredando las líneas:
/* 1. El Layout Maestro (El Padre) define las líneas nombradas */
.layout-maestro {
display: grid;
grid-template-columns:
[full-start] 1fr
[content-start] minmax(0, 800px)
[content-end] 1fr
[full-end];
}
/* 2. El Componente Hijo ocupa todo el ancho */
.componente-banda {
grid-column: full-start / full-end;
background-color: #f1f5f9;
/* Se vuelve un grid y HEREDA la retícula del maestro */
display: grid;
grid-template-columns: subgrid;
}
/* 3. El Nieto usa los nombres de línea del Abuelo */
.banda-contenido-interno {
/* ¡Magia! Este componente conoce las líneas [content-start] y [content-end] */
grid-column: content-start / content-end;
}
Al aplicar grid-template-columns: subgrid, el .componente-banda elimina su frontera espacial. Su contenido interno (.banda-contenido-interno) ahora es capaz de "ver" y anclarse a las pistas nombradas que definió .layout-maestro. Esto es un nivel de desacoplamiento brutal: tu componente ya no necesita saber cuánto mide la pantalla, solo necesita saber en qué líneas debe posicionarse.
El caso de uso estrella: Tarjetas con anatomía perfecta
Es hora de arreglar el desastre que vimos al principio de esta guía. Tenemos tres tarjetas. Una tiene un título muy largo, otra tiene poco texto, y los botones de acción están flotando en diferentes alturas, arruinando el ritmo visual de nuestra interfaz.
¿Cómo logramos que el botón de la tarjeta 1 se alinee perfectamente con el botón de la tarjeta 2, incluso si sus textos tienen longitudes abismalmente distintas? La respuesta es usar subgrid en el eje de las filas (grid-template-rows). Al hacer esto, las tarjetas dejarán de calcular sus alturas de forma aislada y se verán obligadas a sincronizarse a través del contenedor padre.
Para lograr este efecto, tenemos que hacer un pequeño cambio de mentalidad. El contenedor padre (el que envuelve a todas las tarjetas) ya no solo manejará las columnas, también debe administrar las filas de los elementos internos.
Si nuestra tarjeta tiene 4 elementos (Título, Metadata, Párrafo, Botón), le diremos a la tarjeta que debe abarcar 4 filas de su padre usando grid-row: span 4;. Luego, activamos subgrid para que esos 4 elementos internos se encajen en esas 4 filas prestadas. Mira el código solucionado:
/* 1. EL CONTENEDOR PADRE */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* Definimos explícitamente el tamaño de las 4 filas que compartiremos */
grid-template-rows: auto auto 1fr auto;
gap: 1.5rem;
}
/* 2. LA TARJETA HIJA */
.card {
display: grid;
/* La tarjeta debe estirarse para ocupar 4 filas del contenedor padre */
grid-row: span 4;
/* LA MAGIA: Heredamos la estructura de las filas del padre */
grid-template-rows: subgrid;
/* Nota: el 'gap' en las filas ahora se hereda del padre automáticamente */
border: 1px solid #e2e8f0;
border-radius: 8px;
background: #ffffff;
padding: 1.25rem;
}
/* 3. ELEMENTOS INTERNOS (Opcional, pero buena práctica) */
.card h3, .card span, .card p, .card button {
/* Se colocarán automáticamente en cada una de las 4 filas heredadas */
margin: 0;
}
Comentarios y Valoraciones
No hay comentarios aún. ¡Sé el primero en opinar!