wandres.dev
SUBGRID · Heredar las pistas del padre

Herencia de gaps y de nombres de línea

Qué hereda un subgrid además de los tamaños: el gap del padre y sus nombres de línea. Cómo sobrescribir el gap, dónde cae la línea del subgrid dentro del hueco, y cómo añadir nombres locales.

⏱ 17 min

Un subgrid no hereda solo el tamaño de las pistas: hereda también el gap del padre y todos sus nombres de línea. Esas dos herencias son las que hacen que un subgrid encaje visualmente sin ajustes y que un componente pueda colocarse por nombre sin saber en qué posición de la rejilla está. Y las dos se pueden sobrescribir localmente, con un efecto sobre el hueco que conviene entender antes de usarlo.

🎯 Al terminar esta lección sabrás
  • Explicar qué gap usa un subgrid por defecto y cómo se sobrescribe.
  • Situar la línea del subgrid dentro del hueco del padre.
  • Usar los nombres de línea heredados del padre dentro del subgrid.
  • Añadir nombres locales tras la palabra subgrid, incluso con repeat().

El gap se hereda, y dónde cae la línea

Los valores de gap, row-gap y column-gap del padre se transmiten al subgrid en el eje subdividido. Sin escribir nada, la separación entre las pistas del subgrid es la misma que entre las del padre, con lo que todo encaja de entrada.

.rejilla {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 20px;
}
.item {
  grid-column: 2 / 6;
  display: grid;
  grid-template-columns: subgrid;
  /* sin declarar gap: usa los 20px del padre */
}

Puedes sobrescribirlo declarando tu propio gap en el subgrid, y solo afecta al eje que declares:

.item {
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
  row-gap: 0;          /* filas pegadas dentro del subgrid */
  /* column-gap sigue siendo el heredado */
}

Un detalle explica el efecto visual de sobrescribir el gap. Una línea del padre no es una posición sin grosor cuando hay gap: es una separación con anchura. La línea del subgrid se sitúa en el centro de ese hueco.

Con gap: 20px en el padre, el subgrid recibe su línea a 10px de cada lado del hueco. Si el subgrid declara row-gap: 0, sus dos pistas se juntan en ese punto central y recuperan los 20px que ocupaba el hueco, repartidos a los dos lados. El efecto es idéntico al de aplicar un margen negativo: el contenido del subgrid invade el espacio del hueco del padre.

Es una técnica útil cuando quieres que un elemento del subgrid ocupe visualmente el hueco —un separador, un fondo continuo, una imagen a sangre— y es una fuente de sorpresas cuando lo pones sin saberlo.

💡
Inspecciónalo en DevTools

El superpuesto de grid dibuja las líneas del padre y las del subgrid a la vez. Con gap distinto en los dos, ves claramente que la línea del subgrid está en el centro del hueco del padre. Es la forma más rápida de entender el efecto sin razonarlo.

Los nombres de línea también se heredan

Todos los nombres que el padre haya dado a las líneas del eje subdividido están disponibles dentro del subgrid, con la misma raíz. Incluye los nombres implícitos que generan las áreas.

.rejilla {
  display: grid;
  grid-template-columns:
    1fr 1fr 1fr [contenido-inicio] 1fr 1fr 1fr [contenido-fin] 1fr 1fr 1fr;
  gap: 20px;
}
.item {
  grid-column: 2 / 8;
  display: grid;
  grid-template-columns: subgrid;
}
/* Se coloca usando nombres que definió el abuelo */
.subitem { grid-column: contenido-inicio / contenido-fin; }

Esto es lo que hace que un componente con subgrid pueda ser genuinamente reutilizable: colocas el componente donde sea, y su contenido se ancla a las líneas nombradas del sistema, no a números que dependen de dónde acabó.

Nombres locales tras la palabra subgrid

Además de los heredados, el subgrid puede definir sus propios nombres. Van entre corchetes justo después de la palabra clave, uno por línea, empezando por la línea 1 del subgrid:

.item {
  display: grid;
  grid-column: 2 / 8;
  grid-template-columns: subgrid [a] [b] [c] [d] [e] [f];
}

Tres reglas gobiernan esta lista.

Se asignan uno por línea, empezando por la 1 del sistema de coordenadas local del subgrid, no del padre.

Los nombres sobrantes se ignoran. Si escribes ocho nombres para seis líneas, los dos últimos no hacen nada y no es un error.

Se añaden a los heredados, no los sustituyen. Una línea puede llamarse a la vez contenido-inicio por herencia y a por definición local, y ambos nombres funcionan.

También puedes usar repeat() en esa lista, con una variante restringida que solo admite nombres y no tamaños:

/* Nombra todas las líneas del subgrid, sean las que sean */
.fila {
  display: grid;
  grid-column: span 5;
  grid-template-columns: subgrid repeat(auto-fill, [col]);
}
.fila > .tercera { grid-column: col 3; }

En un eje subdividido, auto-fill no cuenta cuántas pistas caben: repite el nombre las veces necesarias para cubrir la amplitud declarada del subgrid. Es la forma de escribir un componente que funciona con cualquier span sin repetir nombres a mano.

Cuándo un subgrid deja de serlo

Hay una regla que conviene conocer porque produce fallos silenciosos. Si no hay rejilla padre, o si el elemento está forzado a establecer un contexto de formato independiente, el valor subgrid se usa como si fuera none y el elemento pasa a ser una rejilla normal.

Los dos casos que provocan eso en la práctica son position: absolute y el confinamiento de layout con contain: layout o contain: content.

/* Esto NO es un subgrid: contain: layout lo fuerza a ser independiente */
.item {
  display: grid;
  grid-template-columns: subgrid;
  contain: layout;         /* rompe la herencia de pistas */
}

Tiene sentido: el confinamiento de layout es una promesa de que nada de dentro afecta a nada de fuera, y un subgrid hace exactamente lo contrario —sus contenidos participan en el dimensionado de las pistas del padre. Las dos cosas son incompatibles por definición. Lo mismo con un elemento absolutamente posicionado, que ni siquiera es un elemento grid.

El síntoma es que la alineación deja de funcionar sin ningún mensaje. Si tu subgrid no alinea, comprueba antes que nada si alguien ha puesto contain o position: absolute en la cadena.

Subgrid invierte el flujo de información del layout, y ese es su verdadero coste

La especificación describe subgrid con una frase que merece leerse dos veces: pasa parámetros de rejilla hacia abajo por los elementos anidados, y devuelve información de dimensionado basada en el contenido hacia arriba, a la rejilla padre. Esa segunda mitad es la interesante y es lo que lo distingue de una herencia normal. Los hijos de un subgrid no solo reciben pistas: contribuyen a dimensionarlas. El título de la tercera tarjeta influye en la altura de una pista que pertenece al abuelo y que afecta a las otras dos tarjetas. Eso convierte al layout en un sistema con dependencias bidireccionales que atraviesan varios niveles del árbol, y explica de golpe tres cosas: por qué contain: layout es incompatible con subgrid, por qué las implementaciones tardaron años en llegar después de que la sintaxis estuviera decidida, y por qué el coste de cálculo de una rejilla con subgrids es superior al de la misma rejilla sin ellos. También sugiere una disciplina de uso: subgrid es una herramienta de alineación, no de estructura. Si te encuentras anidando tres niveles de subgrid para construir la disposición de una página, casi con seguridad hay un modelo más simple con áreas nombradas. Reserva subgrid para el caso que motivó su existencia —hacer que contenidos hermanos se alineen sin aplanar el marcado— y tendrás toda la ganancia con una fracción del coste.