Estructuras de control (II). @each y mapas.

Llegados a este artículo vamos a desarrollar aquí dos conceptos que, en principio, parecen muy dispares, pero es difícil entender uno sin el otro. Vamos a ver como crear unas estructuras de datos complejas, llamadas mapas, y como usar la directiva @each para gestionar dichos mapas de una forma eficiente.

Conceptualmente, si has usado matrices en lenguajes como PHP o Python, lo único que tienes que aprender aquí es la sintaxis específica de SASS. Si no las usado, no te preocupes. Aquí vas a aprender a usar estas estructuras de una forma muy fácil, para sacarle todo el rendimiento posible.

Una vez que estés familiarizado con lo que vamos a exponer aquí (y es más fácil de lo que parece), serás capaz de escribir un código extremadamente compacto, elegante y mantenible. Si bien hemos tenido esto como objetivo en todos los artículos anteriores, aquí entramos en otro nivel. El conocimiento de lo que aquí vamos a exponer distingue a «alguien que escribe una hoja de estilos» de un frontender hecho y derecho. Vamos a ello.

LOS MAPAS EN SASS

Hasta ahora hemos empleado algunos tipos primitivos de datos en SASS, como cadenas ("hola"), colores (red, #EF4512, rgb(120, 1, 17) o rgba(23, 230, 65, .3)) o números (64). Ahora vamos a aprender a crear y usar mapas. Los mapas de SASS son colecciones de valores, separados por comas, en las que cada valor está referenciado por una clave. La sintaxis general de un mapa es la siguiente:

$NombreDelMapa: (clave_1: valor_1, clave_2: valor_2, clave_3: valor_3, ..., clave_n: valor_n);

Como ves, los mapas se definen con un nombre que los identifica, como si fueran variables. En realidad es lo que son: variables cuyo valor es una colección de variables. Las claves suelen ser cadenas o números. Los valores pueden ser cualquier tipo de dato (incluso, como veremos más adelante, otros mapas).

Por ejemplo, podemos tener un mapa cuyas claves sean números y cuyos valores sean colores, así:

$ColorsMap: (1: red, 2: blue, 3: green);

Este sería un ejemplo de un mapa llamado $ColorsMap (el nombre es el que tú quieras darle, en función del uso al que lo vayas a destinar), correctamente definido.

LEER UN MAPA CON @each

Ahora que ya sabes cómo declarar un mapa, tenemos que ser capaces de leerlo. Y, dado que cada valor en un mapa está formado por una clave y el propio valor, no tendría ningún sentido si no fuéramos capaces de leer ambos datos de forma independiente.

La directiva @each nos permite leer los pares clave:valor de un mapa, asignando la clave a una variable, y el valor a otra. El mapa se lee cíclicamente, de modo que, en cada iteración, estas variables recogen los datos del siguiente par clave:valor. La sintaxis genérica para leer un mapa con esta directiva es la siguiente:

@each $key, $value in $ExampleMap {
    /* Procesos a llevar a cabo con las variables
    donde se alamacena la clave ($key, en este ejemplo)
    y el valor ($value, en este ejemplo) */
}

Como ya puedes deducir, la directiva @each, con la sintaxis especificada, está creando un bucle. En cada iteración tenemos un par clave:valor. La clave se almacena en la primera variable que hemos declarado y el valor en la segunda ($key y $value, respectivamente, en este ejemplo). Dentro del cuerpo del bucle podemos usar estas variables para construir otras variables, selectores, o lo que nos haga falta.

UN EJEMPLO PRÁCTICO

Lo anterior está muy bien, pero necesitamos escapar de la mera teoría y darle un uso práctico. Observa el listado map_1.scss:

Cómo ves, el código no puede ser más simple (los comentarios reflejan como se aplica en la práctica la teoría que hemos comentado antes). Ahora llega el momento de transpilar esto a CSS, en map_1.css:

Como ves, es bastante claro. El mapa original tiene tres pares clave:valor, por lo que la directiva @each itera sobre él tres veces, recogiendo un par clave:valor en cada una. Con los datos recogidos, construye un selector y le nutre con una regla CSS. Lee los comentarios del archivo SASS si tienes alguna duda. También te sugiero que repases el artículo dedicado a la interpolación, si no tienes claro cómo se forma cada nombre de selector.

USAR MAPAS DE MAPAS

El ejemplo anterior es muy interesante desde el punto de vista didáctico, pero se nos queda un poco pobre. En realidad, podemos crear todos los selectores que deseemos con la misma mecánica (aunque aquí sólo hayamos creado tres). El problema es que queda muy limitado, porque a cada selector sólo podemos darle una propiedad, debido a que cada elemento del mapa es un par clave:valor, en el que el valor es un simple dato primitivo (un color, en este ejemplo).

Sin embargo, hemos mencionado que los valores de los mapas pueden, a su vez, ser otros mapas. También hemos mencionado que las claves pueden ser números, o cadenas. Con todo esto en mente, podemos crear un ejemplo mucho más potente y sofisticado. Vamos a ver como creamos un mapa de mapas, y como lo recorremos mediante el uso de dos bucle de tipo @each anidados. El listado se llama map_2.scss:

Bueno. Lo primero que ves es que he quitado todos los comentarios, para que vayamos analizando el código poco a poco. En primer lugar observa como creamos un mapa de mapas, en las líneas de la 3 a la 7 (podríamos haberlo puesto todo en una sola línea de código, pero así queda visualmente más claro). Al igual que antes, tenemos un mapa con tres elementos, cuyas claves son 1, 2 y 3. La diferencia es que ahora el valor de cada elementos es, a su vez, un mapa. Este tiene dos elementos, cuyas claves son "background-color" y "border-color", y cuyos valores son los colores que deseemos para el fondo y el borde de cada selector que vayamos a definir.

Lo siguiente que vemos, ya dentro del mixin, es una iteración de tipo @each, que actúa sobre el mapa principal ($SelectorsMap). En cada ciclo, en la variable $key se alamacenará una de las claves de este mapa (1, 2 o 3) y en la variable $value se almacenará uno de los mapas que constituye el valor de la clave por la que se esté iterando. Así, el proceso puede representarse en la siguiente tabla:

ITERACIONES DEL @each EXTERNO SOBRE EL MAPA $SelectorsMap
ITERACIÓN $key $value
1 ("background-color": white, "border-color": red)
2 ("background-color": yellow, "border-color": blue)
3 ("background-color": black, "border-color": orange)

Observa que cada valor es un mapa con dos elementos. Cada uno de ellos tiene, como clave, un nombre de una propiedad CSS y como valor un valor adecuado para dicha propiedad.

Aún dentro del iterador externo, creamos el nombre de un selector, del mismo modo que lo hacíamos en el ejemplo anterior: concatenamos un prefijo con la clave leida en la iteración en curso y, mediante una interpolación, creamos un selector.

Dentro del selector anidamos otra iteración @each, que lee el mapa interno correspondiente. Interpolamos la clave del elemento en curso ("background-color" o "border-color") para formar el nombre de una propiedad, y le asignamos el valor correspondiente).

Y eso es todo. Si lo analizas con detenimiento, verás que no tiene mayor misterio. El quid de todo esto está en tener claro lo que queremos hacer, y definir correctamente los mapas. Cuando transpilas este código, el resultado es map_2.css:

Por supuesto, a las reglas CSS formadas habría que darles más propiedades (no sólo los colores, sino dimensiones, posicionamientos, etc). Todo es cuestión de elaborar el mapa con todos los detalles necesarios. Incluso podría ser que los distintos mapas anidados no tuvieran las mismas propiedades. Por ejemplo, imagina que defines el mapa así:

Dejando como estaba el resto del código SASS, la transpilación sería la siguiente:

Una de las ventajas de usar la interpolación con las claves, así como de la forma en que SASS maneja distintos tipos de datos es que, al definir los mapas, puedes omitir las comillas en los nombres de propiedades, así como en sus valores. Esto hace que, al trabajar con un editor de código, este sea aún más legible. Por ejemplo, el último mapa que hemos definido podríamos haberlo escrito así:

La transpilación a CSS dará el mismo resultado correcto.

CONCLUYENDO

En este artículo hemos aprendido a crear y usar mapa, tanto simples como anidados, y a iterar sobre ellos adecuadamente, empleando la directiva @each. Los ejemplos de código los puedes descargar en este enlace. En los próximos artículos aprenderemos a manejar otros tipos de estructuras de iteración, y veremos cuando nos conviene usar una u otra.

   

Deja un comentario