soy Kseso y esto EsCSS

Guía exhaustiva de colocación de elementos en el Grid Layout

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

✎ 0
COLABORACIÓN AUTOR INVITADO
Ubicación de elementos en el Grid Layout a fondo

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>
Ejemplo de grid lines numeradas
Ejemplo de grid lines numeradas

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 propiedades grid-column-start y grid-column-end
  • grid-row:: Forma acortada de las propiedades grid-row-start y grid-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.

Colocando el ítem usando líneas numeradas del código previo
Colocando el ítem usando líneas numeradas del código previo

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>

Colocando el ítem usando palabra clave span
Colocando el ítem anterior usando span

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>

Ejemplo de ubicación del ítem con números de línea negativos
Ejemplo de ubicación del ítem con números de línea negativos

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>

Ejemplo de colocación del ítem con nombre de línea
Ejemplo de colocación del ítem con nombre de línea

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>

Ejemplo de colocación de ítems con nombre de líneas repetidos
Ejemplo de colocación de ítems con nombre de líneas repetidos

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>

Ejemplo de colocación de ítem expandido hasta la línea nombrada
Ejemplo de colocación de ítem expandido hasta la línea nombrada

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>

Ejemplo de colocación de ítems en áreas del grid
Ejemplo de colocación de ítems en áreas del grid

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>

Colocación del ítem usando nombres implícitos del Grid área
Colocación del ítem usando nombres implícitos del Grid área

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.

Ejemplo de Grid implícita
Ejemplo de Grid implícita

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;)

Ejemplo de Grid implícita extendida
Ejemplo de Grid implícita extendida

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ª.

Ejemplo de Grid implícita previa a la explícita
Ejemplo de Grid implícita previa a la explícita

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>

Ejemplo de Grid implícita nombres de línea de grid no definidas
Ejemplo de Grid implícita nombres de línea de grid no definidas

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>

Ejemplo de Grid implícita usando más nombres de línea de grid de los disponibles
Ejemplo de Grid implícita usando más nombres de línea de grid de los disponibles

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;

Ejemplo de casos especiales de colocación
Ejemplo de casos especiales de colocación

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.

Gran ejemplo de colocación
Gran ejemplo de colocación

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.

Igalia y Bloomberg
Igalia y Bloomberg trabajando juntos por una web mejor

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

Manuel Rego @regocas La totalidad de este artículo es una traducción al español del post original [ING] de Manuel Rego @regocas al amparo de la licencia cc-by-sa original

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.