El modelo de líneas, no el de celdas
Grid no define celdas: define líneas numeradas y tú colocas cajas entre ellas. La numeración, los índices negativos, span, y por qué esta diferencia con las tablas lo cambia todo.
Casi todo el mundo llega a grid pensando en tablas: filas, columnas, celdas donde va el contenido. El modelo real es otro. grid-template-columns no crea columnas, crea líneas, y un elemento se coloca declarando entre qué líneas quiere estar. Las celdas existen, pero son un subproducto. Cambiar de un modelo mental al otro es lo que permite entender por qué un elemento puede solaparse con otro, por qué -1 es un índice útil y por qué colocar algo en la línea 8 de una rejilla de tres columnas es perfectamente legal.
- Explicar la numeración de líneas y su relación con las pistas.
- Colocar un elemento con números positivos, negativos y
span. - Provocar y aprovechar el solapamiento de dos elementos en la misma celda.
- Distinguir el modelo de líneas del modelo de celdas de una tabla.
Líneas, pistas y celdas
Cuando escribes grid-template-columns: 200px 1fr 200px, no defines tres columnas: defines cuatro líneas verticales, y los tres espacios entre ellas son las pistas. Las líneas se numeran desde 1, empezando por el borde de inicio del eje en línea.
línea 1 línea 2 línea 3 línea 4
| 200px | 1fr | 200px |
| pista 1 | pista 2 | pista 3 |
Lo mismo en el otro eje con grid-template-rows. La intersección de una pista de columna y una de fila es una celda, pero la celda no es una entidad que tú manipules: es lo que queda entre cuatro líneas.
Un elemento se coloca diciendo entre qué líneas va:
.rejilla {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
}
.principal {
grid-column: 2 / 3; /* de la línea 2 a la 3 */
grid-row: 2 / 3;
}
grid-column: 2 / 3 significa “empieza en la línea 2, acaba en la 3”, lo que en este caso equivale a ocupar la pista 2. La barra separa inicio de final, y son propiedades abreviadas de grid-column-start y grid-column-end.
En grid-column: 2 / 3 la barra es un separador de sintaxis, igual que en font: 16px/1.5 o en border-radius: 10px / 20px. No hay ninguna operación aritmética. Es una de las pocas veces en CSS que un carácter de operador es puro separador, y a mucha gente le cuesta al principio.
Los índices negativos
Las líneas también se numeran desde el final, con índices negativos. La última línea del grid explícito es -1, la anterior -2, y así hacia atrás.
Esto da el idioma más útil de grid: “de principio a fin, sea cual sea el número de pistas”.
/* Ocupa todas las columnas, tenga las que tenga la rejilla */
.banner { grid-column: 1 / -1; }
Es la declaración que más veces escribirás. Un encabezado que atraviesa una rejilla, un separador, un mensaje de estado a ancho completo: todos son 1 / -1.
Hay una limitación que conviene conocer desde el principio: los índices negativos cuentan solo las líneas del grid explícito. Si un elemento se ha colocado fuera de las pistas que definiste y ha generado pistas implícitas, -1 sigue apuntando al final de las explícitas y no al final visual de la rejilla. Con grid-template-columns: repeat(auto-fill, ...) el grid explícito sí incluye las pistas generadas por la repetición automática, así que ahí 1 / -1 funciona como esperas.
span y la colocación relativa
La tercera forma de colocar es no decir dónde acaba sino cuánto ocupa:
.ancha { grid-column: span 2; } /* dos pistas, donde toque */
.desde-tres { grid-column: 3 / span 2; } /* desde la línea 3, dos pistas */
.hasta-final { grid-column: span 2 / -1; } /* dos pistas terminando al final */
span sin número de línea deja que el algoritmo de colocación automática decida el punto de partida, lo que hace el elemento portable: funciona en cualquier posición de la rejilla. Con un número de línea, fijas el punto de anclaje y span define el tamaño.
La combinación de span con la colocación automática es la base de las rejillas editoriales donde algunos elementos son grandes y otros pequeños sin que nadie los coloque a mano.
.galeria {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}
.galeria > .destacada { grid-column: span 2; grid-row: span 2; }
Lo que las tablas no pueden hacer
La diferencia con el modelo de celdas de una tabla no es académica. Tres cosas son posibles en grid y no en una tabla.
Solapamiento. Dos elementos pueden ocupar la misma celda. No hay ninguna regla que lo impida, y el orden de pintado se resuelve por orden de documento y z-index como en cualquier otro sitio. Es la forma canónica de superponer un texto sobre una imagen sin position: absolute:
.portada {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
}
.portada > * {
grid-area: 1 / 1; /* todos en la misma celda */
}
.portada .titulo {
align-self: end;
z-index: 1;
}
Ese grid-area: 1 / 1 colocando todo en la misma celda es un patrón enormemente útil: da superposición con altura intrínseca, cosa que position: absolute no da porque el elemento absoluto no contribuye al tamaño del padre.
Orden independiente de la fuente. Un elemento que aparece el último en el HTML puede colocarse en la primera celda. En una tabla, el orden del marcado es el orden visual sin excepciones. Esto arrastra el mismo problema de accesibilidad que order en flex, con la misma regla: es legítimo para disposición, no para jerarquía.
Huecos deliberados. Puedes dejar celdas vacías simplemente no colocando nada en ellas. Una tabla exige una celda por cada intersección.
Los datos tabulares deben ir en una tabla, no en un grid. Una tabla comunica a los lectores de pantalla la relación entre una celda y sus encabezados de fila y columna, y permite navegar por esa relación. Un grid es geometría sin semántica. Que puedas hacer que parezca una tabla no significa que debas.
La decisión de definir grid sobre líneas y no sobre celdas es lo que separa a este modelo de todo lo anterior en CSS, y merece la pena ver por qué. Cuando defines celdas, el layout es una estructura de datos: una matriz que hay que rellenar, con una casilla por elemento y sin sitio para nada más. Cuando defines líneas, el layout es un sistema de coordenadas, y un elemento es un rectángulo definido por dos pares de coordenadas. Eso permite inmediatamente cosas que en una matriz son imposibles de expresar: rectángulos que se solapan, rectángulos que dejan huecos, rectángulos de tamaños arbitrarios, y la posibilidad de nombrar coordenadas en lugar de contarlas. Todo lo que grid puede hacer y ningún modelo anterior podía —áreas nombradas, colocación automática, subgrid, densidad— se deriva de haber elegido coordenadas en vez de casillas. Y hay una consecuencia práctica para tu forma de trabajar: en un sistema de coordenadas puedes razonar sobre el layout sin ejecutarlo. Puedes dibujar la rejilla en papel, anotar las coordenadas de cada elemento y saber exactamente qué va a pasar, cosa que con flotantes o con position: absolute era literalmente imposible porque el resultado dependía de un algoritmo de flujo con demasiado estado. Grid es el primer modelo de layout de CSS que se puede diseñar antes de escribirlo, y esa es la razón real de que las herramientas de diseño y el código por fin hablen el mismo idioma.