Guía exhaustiva de colocación de elementos en el Grid Layout 7.2.16
Revisión exhaustiva de los diferentes métodos proporcionados por las especificaciones del CSS Grid Layout para colocar elementos en la rejilla.
Guía exhaustiva de colocación de elementos en el Grid Layout
Lo que te dispones a leer es la traslación al español del artículo original "Deep Dive into Grid Layout Placement" de Manuel Rego @regocas. Todas las imágenes, excepto la inicial, también son de su autoría.
Durante los últimos meses, como parte de mi trabajo en Igalia, he estado centrado en terminar de implementar en Blink las novedades de la especificación CSS Grid Layout relacionados con la colocación de ítems. En resumen, la tarea se relaciona principalmente con 2 aspectos:
- Soporte a la rejilla implícita antes de que se explicite. Por lo que la rejilla puede añadir tracks (el espacio entre dos líneas paralelas) a demanda no sólo en la dirección de crecimiento (generalmente a derecha/abajo), sino también en la contraria.
- Arreglar el uso de nombres de línea no declarados. Este es el caso cuando un elemento se coloca en una línea llamada "foo", pero no existen líneas con ese nombre en la rejilla.
Estos pueden parecer tareas bastante simples, pero implicaban un buen montón de cambios en la implementación subyacente. Terminé refactorizando todo el código para resolver la colocación en la rejilla parrilla con el fin de completarlos. Incluso escribí un documento que explica todo el plan y todos los detalles técnicos, donde se pueden encontrar enlaces a todos los parches relacionados.
Ahora que hemos terminado esto, es el momento de explicar cómo puedes usarlo. Aunque mi colega Sergio ya escribió sobre esto en 2014, la especificación ha cambiado desde ese momento, por lo que creo que es mejor tratar de explicar todo el asunto desde el principio. Este post es una especie de resumen de ejemplos de la sección "Placing Grid Items" de la especificación CSS Grid Layout.
Grid lines
Este es probablemente uno de los conceptos más importantes de la especificación del Grid Layout. Las líneas de la cuadrícula son las que dividen horizontal y verticalmente una cuadrícula. Y en realidad están numeradas, empezando por 1.
Vamos a utilizar una cuadrícula de 3x2 como ejemplo para explicar cómo funciona esto:
<div style="
display: grid;
grid-template-columns: 300px 200px 100px;
grid-template-rows: 100px 50px;">
</div>
Propiedades de emplazamiento en el Grid
Con el fin de colocar los elementos en el interior del contenedor de cuadrícula, es necesario utilizar las propiedades para la ubicación en la rejilla. Estas propiedades son:
grid-column-start
: Establece la primera línea vertical para el item.grid-column-end
: Establece la última línea vertical para el item.grid-row-start
: Establece la primera línea horizontal para el item.grid-row-end
: Establece la última línea horizontal para el item.
Con estas propiedades se define el área donde se colocará el elemento en el grid. Con el fin de hacer eso, se utilizan los números de línea.
El valor inicial de estas propiedades es automático, lo que hace posible que los elementos se coloquen automáticamente en busca de celdas vacías dentro de la red. Para obtener más información sobre esto, por favor revisa el post anterior sobre este punto.
Además de estas, están las prácticas formas acortadas:
grid-column
: Forma acortada de las propiedadesgrid-column-start
ygrid-column-end
grid-row:
: Forma acortada de las propiedadesgrid-row-start
ygrid-row-end
grid-area:
Forma acortada para declarar las 4 propiedades de emplazamiento en con una sola.
Ahora imagina que añades el siguiente ítem en el gid anterior (código 1):
<div style="
grid-column-start: 2;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end 2;">
</div>
Probablemente más fácil de leer si utilizas la forma acortada:
<div style="grid-column: 2 / 4; grid-row: 1 / 2;"></div>
Esto significa que el elemento del grid se colocará ocupando las columnas 2ª y 3ª en la primera fila.
Cubriendo celdas
El ítem abterior abarca 2 columnas (2ª y 3ª) referenciadas por las líneas. Se podría hacer lo mismo usando la palabra clave span
, junto con el número de celdas que se desean cubrir.
Por lo tanto, se puede colocar el elemento en la misma posición declarando:
<div style="grid-column: 2 / span 2; grid-row: 1;"></div>
Ten en cuenta que aquí no se está configurando la línea final de la fila. Esto significa que grid-row-end
toma un valor auto
. En este caso auto
cubre una por defecto.
Número de línea negativos
Hasta ahora sólo hemos visto números positivos, pero las líneas también tienen índices negativos. Los números negativos permiten hacer referencia a las líneas comienzando por el final de la rejilla.
Siguiendo con el mismo ejemplo, se podría colocar el elemento de nuevo en la misma posición utilizando índices negativos:
<div style="grid-column: -3 / -1; grid-row: -3 / -2;"></div>
Esto puede ser muy útil en algunas situaciones. Por ejemplo, si quieres estar seguro de que el elemento estará en la última columna, independientemente del número de tracks
(el espacio entre dos líneas paralelas adyacentes), sólo tienes que declarar: grid-column-end: -1;
Líneas del Grid con nombre
No sólo eso, sino que también se puede dar nombres a las líneas de la cuadrícula (Named lines gid
), por lo que no es necesario recordar el número específico para hacer referencia a ellos.
Vamos a modificar la conformación de la rejilla manteniendo el tamaño de los tracks añadiendo nombres a las líneas:
<div style="
display: grid;
grid-template-columns: [start] 300px [main] 200px [aside] 100px [end];
grid-template-rows: [top] 100px [middle] 50px [bottom];">
</div>
Y de nuevo, si queremos poner el ítem en la misma posición, sólo tenemos que hacer referencia al nombre de las líneas:
<div style="grid-column: main / end; grid-row: top / middle;"></div>
Una línea puede tener varios nombres, sólo tiene que ponerlos en la definición:
grid-template-rows: [top start] 100px [middle center] 50px [bottom end];
Los nombres de las líneas también se pueden repetir. Para hacer referencia a ellos tienes que utilizar un número que puede ser, de nuevo, positivo o negativo. Vamos a usar un ejemplo diferente para ilustrar esto:
<div style="
display: grid;
grid-template-columns: [col] 200px [gap] 50px [col] 200px [gap] 50px [col] 200px [gap];">
</div>
E imagina que colocas algunos ítems así:
<div style="grid-column: col 2;"></div>
<div style="grid-column: col 1 / gap 2;"></div>
<div style="grid-column: col -1;"></div>
Y, por supuesto, puede extenderse hasta una línea de la cuadrícula con nombre:
<div style="grid-column: col 2 / span 2 gap;"></div>
Grid areas
Mejor aún, puedes definir áreas en la cuadrícula y colocar los items directamente en ellas. Para ello tienes que utilizar la propiedad grid-template-areas
para poner nombres a las diferentes áreas de la rejilla. Y se podría utilizar la forma acortada grid-area
directamente paraa colocar los elementos.
Vamos a utilizar una cuadrícula grande (5x4) para mostrar un ejemplo:
<div style="
display: grid;
grid-template-columns: 100px 100px 100px 100px 100px;
grid-template-rows: 100px 100px 100px 100px;
grid-template-areas:
'title title title title aside'
'nav main main main aside'
'nav main main main aside'
'footer footer footer footer footer';">
</div>
Y colocar un elemento en cada una de las áreas:
<div style="grid-area: title;"></div>
<div style="grid-area: nav;"></div>
<div style="grid-area: main;"></div>
<div style="grid-area: aside;"></div>
<div style="grid-area: footer;"></div>
Grid áreas y líneas con nombre
Un aspecto interesante de las áreas y la colocación es que las grid areas crean nombres implícitos para las líneas del grid que las rodean. Estos nombres implícitos usan los sufijos -start
y -end
. Y se puede hacer referencia a esas líneas al colocar un elemento, en lugar de utilizar todo el área.
Por ejemplo, el área tittle
del ejemplo anterior crea 4 nombres implícitos para las líneas (2 por eje):
- línea izquierda:
title-start
- Línea derecha:
title-end
- Línea superior:
title-start
- Línea inferior:
title-end
Siguiendo con éste ejemplo podrías colocar un elemento utilizando los nombres implícitos:
<div style="grid-column: main-start / aside-end;
grid-row: title-start / nav-end;">
</div>
Y puedes hacer lo mismo al revés. Si nombras líneas utilizando los sufijos, en realidad estás creando áreas implícitas. Por lo tanto, podríamos crear la misma rejilla usando líneas del grid con nombre:
<div style="display: grid;
grid-template-columns: [title-start nav-start footer-start] 100px [main-start nav-end] 100px 100px 100px [aside-start title-end main-end] 100px [aside-end footer-end];
grid-template-rows: [title-start aside-start] 100px [nav-start main-start title-end] 100px 100px [footer-start nav-end main-end aside-end] 100px [footer-end];">
</div>
Todos los ejemplos de items ubicados en este apartado serían colocados exactamente en el mismo lugar usando esta nueva cuadrícula.
Grid implícita
Con las propiedades que definen el grid (grid-template-columns, grid-template-rows y grid-template-areas
) determinas el número de tracks
explícitas (columnas y filas) en la cuadrícula. Sin embargo, las especificaciones de la rejilla te permiten colocar elementos que estén fuera del grid explícito. Para lograr esto, las tracks
implícitas son creadas automáticamente, el tamaño de estas tracks
es controlado por las propiedades grid-auto-columns
y grid-auto-rows
[ver spec]. En los siguientes ejemplos voy a utilizar el color rojo para resaltar las líneas implícitas.
Esta vez vamos a usar un grd simple de 2x1
<div style="display: grid;
grid-template-columns: 200px 200px;
grid-auto-columns: 100px;">
</div>
Imaginar que se coloca un elemento en quinta columna (grid-column: 5;
). Como la rejilla tiene solamente 2 columnas se añadirán 3 columnas implícitoas con el fin de posicionar el elemento.
Una vez más, también puedes crear tracks
implícitas con los items que abarcan varias celdas. Por ejemplo, si un ítem cubre 3 columnas a partir de la segunda (grid-column: 2 / span 3;
)
Originalmente, las tracks
implícitas sólo se podían añadir al final. Pero ahora es posible añadir pistas implícitas antes de la rejilla explícita. Por ejemplo, si colocas un elemento utilizando grid-column: -5;
se van a añadir 2 columnas a la izquierda y será colocado en la columna -2ª.
Grid implícita y nombre de líneas del grid
Pero esta no es la única manera de crear tracks implícitas, también puedes crearlos si utilizas nombres no definidos en las líneas del grid. Esto es más una forma de mostrar los errores en el CSS de usuario que una novedad en sí misma, pero tal vez a alguien le resulta útil. La idea es que todas las líneas de la cuadrícula implícita tendrían algún nombre aleatorio que podría utilizarse para posicionar un ítem.
El ejemplo básico es colocar elementos haciendo referencia a una línea inexistente llamada foo
. Por ejemplo, creará 3 columnas implícitas (1 antes y 2 después de la rejilla explícita) con los siguientes elementos:
<div style="grid-column: foo;"></div>
<div style="grid-column: 2 / span 2 foo;"></div>
<div style="grid-column: -1 foo;"></div>
Ten en cuenta que en este ejemplo tan simple grid-column: foo
está siendo colocado en la cuarta columna (añadiendo una columna adicional en blanco, justo después de la rejilla explícita). Esto se debe a que la primera línea que se considera para ser llamada foo
es la primera línea implícita (línea 4), por lo que la última línea de la parrilla (línea 3) no está incluida.
Además el último ítem grid-column: -1 foo
se coloca en la columna -1ª (tal vez no te lo esperabas). Esto se debe a que empiezas a buscar una línea llamada "foo" desde el borde del grid explícita. Así que ignora las líneas -1, -2 y -3 (ya que no se llaman "foo") y considera la línea 4 (primera línea de la parrilla implícita) para tener ese nombre.
Esto se complica un poco más si la línea ya existe realmente, ya que la has de contar también para colocar el elemento. Especialmente es complejo si la estás utilizando para extender el ítem hasta una línea del grid con nombre y no hay las suficientes líneas. En ese caso, sólo las líneas implícitas en la dirección de búsqueda se tienen en cuenta para ese nombre.
Una vez más, espero que un ejemplo puede ayudarte a entender esto. Vamos a añadir un nombre a la línea central del ejemplo anterior:
<div style="display: grid;
grid-template-columns: 200px [middle] 200px;
grid-auto-columns: 100px;">
</div>
Y ahora coloquemos algunos items usando esa línea "central" como referente:
<div style="grid-column: 3 middle;"></div>
<div style="grid-column: span 2 middle / 5;"></div>
<div style="grid-column: -4 / span middle;"></div>
Lo extraño en este caso es grid-column: span 2 middle / 5;
que como puedes ver va desde la colomna -1ª hasta la 4ª (ambas incluidas). El ítem termina en la línea 5, y tiene que abarcar 2 líneas llamadas "middle" para encontrar su inicio. Se podría pensar que se debe contar con la línea 4 y la línea 2, pero, como se explicó antes, tienes que empezar a contar las líneas desde borde de la rejilla explícita. La que en realidad cuenta es la línea 2 y luego tienes que considerar las líneas implícitas a la izquierda para encontrar la posición de inicio (línea -4).
Casos especiales
Las propiedades de la ubicación en la rejilla tienen algunas situaciones especiales que se solventan en la sección "resolución de conflictos" de la especificación.
Por ejemplo, si se coloca un ítem donde la línea donde termina es anterior a la línea donde comienza se intercambian las líneas. Así si declaras grid-column: 5 / 2;
deviene en grid-column: 2 / 5;
Otra situación es aquella en la que hay span
en medio de la posición de inicio y final. El span
para la posición final se descarta. Por lo tanto grid-column: span 2 / span 3;
se convierte en grid-column: span 2;
. En este caso se utilizará el algoritmo de ubicación de la rejilla para encontrar un área vacía (de 2 columnas en este ejemplo concreto) para posicionarse él mismo.
El último es el caso en el que sólo hay un span
para denominar la línea del grid. En ese caso, es reemplazado por span 1
. E.g. grid-column: span foo;
se convertirá en grid-column: span 1;
Recapitulación
Si has sido capaz de llegar leyendo hasta aquí significa que estás interesado en el CSS Grid Layout. La conclusión principal es que la especificación es muy flexible en cuanto a cómo colocar los elementos en la rejilla. Como se puede ver hay un buen montón de maneras diferentes para colocar un elemento en el mismo lugar. Probablemente cada cual se acostumbrará a algunos de ellos y simplemente se olvidará del resto.
En mi humilde opinión lo básico (line indexes, spans, line names & areas) es bastante sencillo. Y el grid implícito tampoco es tan difícil tampoco. A continuación, los índices negativos vienen con cierta diversión. Sin embargo el comportamiento de las líneas del grid sin nombre es realmente complicado (afortunadamente es algo que no debería preocuparte demasiado). Pero es verdad que no soy imparcial, ya que he estado lidiando con esto desde hace mucho tiempo.
Por último, pensé que estaría bien terminar con un gran ejemplo que utilizase la mayoría de las cosas descritas en este post. Si logras hacerlo bien en lugar de sólo estar completamente confuso tú eres un "master genius" de la colocación en el Grid Layout. Enhorabuena
Esta es la definición del grid layout usado en el ejemplo:
<div style="
display: grid;
grid-template-columns: [left] 200px [main-start] 100px [center] 100px 100px [main-end] 50px 50px [right];
grid-template-rows: [top title-start] 50px [title-end main-start] 200px [main-end center] 150px 100px [bottom];
grid-auto-columns: 50px;
grid-auto-rows: 50px;">
</div>
Y en la siguiente imagen se puede ver cómo son colocados los diferentes elementos.
Puedes probarlo en vivo en nuestro repositorio de ejemplos: http://igalia.github.io/css-grid-layout/grid-placement.html
Estatus
Como se ha comentado en la introducción la implementación en Blink actual debería soportar ahora (Chrome 50+) todas estas posibilidades de colocación. Igalia ha estado trabajando en ello y ahora estamos portándolo a WebKit también.
Por otro lado, ya Gecko ya le da soporte también, en este caso desarrollado por Mozilla.
Por último, como siempre, me gustaría destacar una vez más que todo este trabajo ha sido realizado como parte de una colaboración entre Igala y Bloomberg. ¡Muchas gracias por su apoyo!
Créditos y Autoría
Deep Dive into Grid Layout Placement
publicado originalemnte el 1 de Febrero de 2016 en Igalia.Todo, código e imágenes incluídas (excepto la inicial), provienen de dicho artículo.
Yo sólo aporto, con mis disculpas, los errores de traducción e interpretación.
Lista de lectura de artículos sobre el CSS Grid Layout
Si estás interesado en conocer y dominar el CSS Grid Layout te serán de ayuda esta relación de artículos publicados en el blog hasta la fecha.
Y si eres de los que creen que aún es pronto, que el tema está verde, recuerda que las previsiones son que el módulo CSS Grid Layout alcance el estatus CR durante este mes de Febrero.