wandres.dev
SUBGRID · Heredar las pistas del padre

Límites, soporte y el fallback

Dónde está subgrid en 2026, qué no hace y nunca hará, cómo se compara con display contents, el coste de cálculo real y cómo escribir una degradación que no dependa de él.

⏱ 17 min

Subgrid llegó a los tres motores repartido en cuatro años: Firefox en 2019, Safari en 2022, Chrome en 2023. En 2026 está ampliamente disponible y se puede usar sin reservas en producción, pero conviene tener claro qué problemas no resuelve, por qué su coste de cálculo no es despreciable y cómo escribir una versión degradada que siga siendo usable, porque la degradación de un layout de alineación tiene que ser deliberada o queda peor que no haber alineado nada.

🎯 Al terminar esta lección sabrás
  • Situar el estado de soporte de subgrid y su fecha de disponibilidad.
  • Enumerar tres cosas que subgrid no hace y por qué.
  • Comparar subgrid con display: contents y elegir entre los dos.
  • Escribir un fallback con @supports que degrade de forma útil.

El soporte

Firefox lo implementó primero, en la versión 71 de diciembre de 2019, y estuvo solo durante casi tres años. Safari 16 lo trajo en septiembre de 2022. Chrome y Edge, en la 117 de septiembre de 2023. Desde ese momento está en los tres motores, y con el margen de estabilidad habitual entró en la categoría de ampliamente disponible durante 2026.

En términos prácticos: puedes usarlo directamente en cualquier proyecto nuevo. Solo necesitas un fallback si tu producto tiene una base medible de navegadores anteriores a otoño de 2023, cosa que en 2026 solo ocurre en entornos corporativos con versiones congeladas.

📝
Las DevTools ayudan más de lo habitual

El inspector de rejilla de Firefox distingue visualmente un subgrid de una rejilla independiente y dibuja las dos capas de líneas superpuestas. Chrome también los identifica. Es la herramienta más rápida para verificar que tu subgrid es realmente un subgrid y no una rejilla que se ha quedado en normal por alguna de las condiciones que lo desactivan.

Lo que subgrid no hace

No es masonry. El layout tipo mampostería, donde los elementos se apilan verticalmente rellenando huecos como en un muro de piedra, no es lo que hace subgrid ni se puede construir con él. Masonry sigue siendo una discusión abierta en el grupo de trabajo, con propuestas sintácticas en competencia, y solo está disponible detrás de banderas experimentales. No cuentes con ello en producción; lo que existe hoy son grid-auto-flow: dense con sus limitaciones o una implementación en JavaScript.

No alinea elementos arbitrarios. Un subgrid solo puede alinearse con las pistas de su propio ancestro. No hay forma de alinear dos elementos de ramas distintas del árbol, ni de decir “alinéate con aquel otro”. La relación es siempre estructural, y esa restricción es intencionada.

No sobrevive al confinamiento ni a la posición absoluta. Como ya viste, contain: layout, contain: content y position: absolute fuerzan un contexto de formato independiente, y en ese caso subgrid se usa como none. Es incompatible por definición: subgrid necesita propagar información de dimensionado hacia arriba y el confinamiento existe precisamente para impedirlo.

No es gratis. Los contenidos del subgrid participan en el cálculo de tamaño de las pistas del padre, lo que crea una dependencia bidireccional que atraviesa niveles del árbol. En una rejilla con muchas filas y subgrids en todas, la diferencia con la misma rejilla sin subgrid es medible en el perfilador. No es motivo para no usarlo, pero sí para no anidarlo tres niveles sin necesidad.

display: contents, la alternativa parcial

display: contents resuelve el mismo problema de otra forma: elimina la caja del elemento intermedio y promueve a sus hijos a elementos del abuelo. Como pasan a ser hijos de verdad, se alinean.

/* Los hijos de .campo se convierten en elementos de .formulario */
.campo { display: contents; }

La comparación es directa y la decisión es fácil:

display: contents subgrid
alinea entre hermanos
conserva borde, fondo y relleno del intermedio no
permite gap propio en el intermedio no
permite un layout distinto dentro no
coste de cálculo menor mayor

La fila decisiva es la segunda: si el elemento intermedio tiene cualquier estilo visual propio —un borde, un fondo, un radio, un relleno, una sombra— display: contents lo hace desaparecer y no hay forma de recuperarlo. Como esa es la situación de casi todas las tarjetas y casi todos los grupos de formulario, subgrid gana en la mayoría de los casos reales.

display: contents sigue siendo útil cuando el elemento intermedio es puramente estructural: un contenedor que existe por razones de componente y no tiene ninguna presencia visual. En esos casos es más barato y más simple.

⚠️
Y una precaución de accesibilidad

display: contents sobre elementos con semántica implícita —listas, tablas, sus partes internas— ha tenido históricamente un comportamiento irregular en el árbol de accesibilidad, y la especificación define que en elementos inusuales, como los controles de formulario o los elementos reemplazados, se comporte como none. Los motores han corregido los fallos más graves, pero si lo aplicas sobre un ul o un table conviene verificar con un lector de pantalla que la semántica sigue anunciándose.

Escribir el fallback

La estrategia correcta es escribir primero la versión que funciona en todas partes y mejorarla dentro de un @supports. Así el navegador antiguo no necesita entender nada y el moderno recibe la mejora.

/* Base: sin subgrid. Las tarjetas se alinean solo por abajo,
   con flex y un margen automático. Es una degradación honesta. */
.plan {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1.25rem;
  border: 1px solid #45475a;
  border-radius: 0.75rem;
}
.plan .cta { margin-block-start: auto; }

/* Mejora: alineación completa entre las cuatro filas */
@supports (grid-template-rows: subgrid) {
  .planes { grid-template-rows: auto auto auto auto; }
  .plan {
    display: grid;
    grid-row: span 4;
    grid-template-rows: subgrid;
  }
  .plan .cta { margin-block-start: 0; align-self: end; }
}

Dos detalles importan en este patrón.

El primero: la versión base no intenta imitar el resultado con subgrid. Alinear los botones abajo con margin-block-start: auto es un resultado distinto y perfectamente aceptable, no una imitación defectuosa. Los intentos de reproducir la alineación completa sin subgrid son los que producen recortes de texto y alturas fijas.

El segundo: el bloque @supports deshace lo que la versión base hizo, en este caso el margin-block-start: auto. Un fallback que no se limpia deja dos mecanismos de alineación compitiendo, y el resultado es peor que cualquiera de los dos por separado.

Para detectar el eje de columnas la consulta es la simétrica, y ambas dan el mismo resultado porque ningún motor implementó un eje sin el otro:

@supports (grid-template-columns: subgrid) { }
Una funcionalidad que tarda cuatro años en llegar a tres motores enseña algo sobre cómo evaluar lo nuevo

Subgrid estuvo especificado y con una implementación funcionando en Firefox durante casi tres años antes de que el segundo motor lo enviara. Es un plazo enorme, y la razón no fue desinterés: fue que implementarlo obliga a reescribir el algoritmo de dimensionado de pistas para que acepte contribuciones que vienen de varios niveles más abajo, y hacer eso sin degradar el rendimiento de las rejillas normales es un trabajo de ingeniería considerable. Merece la pena tenerlo presente porque corrige un sesgo muy extendido a la hora de evaluar novedades de la plataforma: la dificultad de una funcionalidad para el que la usa no guarda ninguna relación con su dificultad para el que la implementa. Subgrid es una palabra clave y tardó cuatro años; las custom properties son sintaxis trivial y exigieron rehacer el modelo de valores computados; :has() es un selector de aspecto inocente que estuvo bloqueado más de una década por el coste de la invalidación de estilos. Y al revés, cosas que parecen enormes desde fuera, como añadir un espacio de color nuevo, son relativamente directas. La conclusión operativa para tu forma de trabajar es que el tiempo que una funcionalidad tarda en estar en todas partes no lo puedes predecir desde la sintaxis, así que la única política sostenible es escribir código que degrade bien por defecto y mejorar con @supports, en lugar de esperar a que algo sea universal antes de usarlo. Con esa disciplina, adoptar algo el día que sale no tiene ningún riesgo, y esperar tres años no tiene ninguna ventaja.

⚔️ Cierra el nivel
  1. Monta las tres tarjetas del nivel 20.4 y verifica en DevTools que las cuatro filas son compartidas.
  2. Añade un quinto elemento a una tarjeta sin tocar el span y observa qué pasa exactamente.
  3. Cambia el gap interno de la tarjeta a cero y explica por qué el contenido invade el hueco.
  4. Aplica contain: layout a una tarjeta y comprueba que deja de ser subgrid sin ningún aviso.
  5. Escribe el fallback con @supports, desactiva subgrid en el navegador si puedes, y valora si la degradación es aceptable.
  6. Convierte el formulario a display: contents y enumera exactamente qué has perdido.