Estructuras de control (III). @for y @while.

En este artículo vamos a conocer dos estructuras de control para el uso de bucles en SASS. Los bucles nos permiten crear conjuntos de reglas CSS repetitivas de una forma muy simple. Al transpilar el código SASS a CSS se puede generar una lista de reglas muy amplia habiendo escrito muy pocas líneas de código. Como veremos en este artículo, en combinación con el empleo de pseudo elementos, o de ciertas funciones nativas de SASS, son una herramienta muy potente.

En SASS encontramos dos tipos de bucles: los que se definen con la directiva @for y los que se definen con la directiva @while. En este post vamos a conocer ambos. Verás que son muy fáciles de usar.

LA DIRECTIVA @for

Esta directiva nos permite crear bucles que iteren un número determinado de veces. Dentro del bucle podremos colocar un bloque de código que deba repetirse en cada iteración. El concepto en sí no es nuevo. Son los mismos bucles de tipo for que se emplean en cualquier lenguaje de programación (y, si estás leyendo esto, asumo que sabes de lo que estamos hablando). Lo que sí presenta algunas particularidades es la sintaxis específica de SASS. Los conceptos básicos, como variable de control, y los límites de inicio y final, son los mismos que ya conoces.

En SASS tenemos dos sintaxis para estos bucles. La primera es la siguiente:

@for $variableDeControl from $valorInicial through $valorFinal{
    // Cuerpo del bucle.
    // Conjunto de instrucciones que se repetirán en cada iteración
}

Esto hará que el bucle se inicie asignándole a $variableDeControl el valor de $valorInicial. En cada iteración el valor de $variableDeControl se incrementará en 1. El bucle finalizará cuando el valor de $variableDeControl sea igual a $valorFinal. Esa será la última iteración del bucle.

La otra sintaxis es muy parecida, con una diferencia muy sutil:

@for $variableDeControl from $valorInicial to $valorFinal{
    // Cuerpo del bucle.
    // Conjunto de instrucciones que se repetirán en cada iteración
}

En este caso, el bucle iterará hasta que el valor de $variableDeControl alcance el valor de $valorFinal -1. Es decir. Si partimos de los mismos valores para $valorInicial y $valorFinal en ambos bucles, el primer ejemplo iterará una vez más que el segundo.

Por lo tanto, los dos bucles siguientes serán equivalentes:

@for $i from 1 through 4{
    //Cuerpo del bucle
}

@for $i from 1 to 5{
    //Cuerpo del bucle
}

Ambos ejecutarán cuatro iteraciones.

EJEMPLOS PRÁCTICOS

Vale. Ya conocemos la sintaxis en teoría. Ahora vamos a ver cómo podemos usar estos bucles para generar código CSS. Evidentemente, en el contexto de SASS, lo que de verdad tiene sentido en los bucles es la variable de control para actuar sobre nombres de selectores, o reglas CSS. Esto nos permitirá escribir reglas CSS repetitivas con muy pocas líneas de código SASS. Observa el primer ejemplo, llamado for_1.scss:

Cómo ves, tenemos un bucle que, en cada iteración, genera un selector referido a una clase llamada .item-n, donde n es el valor de la variable de control del bucle. Observa que, para que se genere correctamente el nombre de la clase, debemos interpolar la variable, tal cómo ves en la línea resaltada. El resultado de transpilar este código será el que ves a continuación en for_1.css:

La variable de control podemos usarla, también, para acceder a elementos de un mapa que tengamos predefinido, de modo que integremos los valores del mismo en el código que forma parte del cuerpo del bucle. Lo único que debemos tener en cuenta es que, cómo el valor de la variable de control siempre es numérico, las claves del mapa deben serlo también. Además, si usamos la variable de control para referenciar las claves del mapa, los límites del bucle serán tales que nunca pretendamos acceder a un elemento del mapa que no existe. Por ejemplo, si nuestro mapa tiene cuatro elementos con las claves 1, 2, 3 y 4, nunca podremos permitir que la variable de control sea menor que 1 o mayor que 4, ya que eso generaría un error. Observa el listado for_2.scss:

En la línea 3 ves que tenemos creado un mapa de códigos de color, llamado $colorsMap. Esto, en sí, no tiene nada nuevo. aprendimos a crear mapas en el artículo anterior.

Dentro del cuerpo del bucle, en la línea 6, se generan unas reglas CSS basadas en la variable de control, que luego se aplicarán a sucesivos elementos <div> de un documento HTML. Observa cómo hemos empleado la pseudo clase :nth-of-type(), pasándole la interpolación de la variable de control, para referirnos a distintos elementos de una misma etiqueta. Si tienes dudas sobre el uso de esta pseudo clase te sugiero que le eches un vistazo a este artículo.

En la línea 7 es donde la cosa se pone interesante. Para asignar el valor de la propiedad background-color vamos a recurrir a los valores almacenados en el mapa $colorsMap. Para ello empleamos la función map-get(). Esta es nativa de SASS (no la hemos definido en ninguna parte, sino que forma parte del lenguaje) y se usa para recuperar el valor de un elemento de un mapa. Recibe dos argumentos: el primero es el nombre del mapa del que queremos recuperar un valor, y el segundo es la clave del valor que queremos recuperar. Y esta es la razón por la que, en este ejemplo, el mapa debe tener claves numéricas: porque la clave que usamos en esta función es la variable de control del bucle, que es un valor numérico.

El resultado de transpilar este código lo vemos en for_2.css:

LIMITACIONES EN LOS BUCLES @for

Los bucles @for de SASS tienen algunas limitaciones, que se hacen evidentes si estás familiarizado con los bucles en otros lenguajes de programación. La más evidente es que el incremento de la variable de control se hace siempre de unidad en unidad. No existe, como en otros lenguajes, una cláusula step o similar, que permita contar de dos en dos, o de tres en tres, etc. Por la misma razón, las cuentas no pueden ser descendentes, es decir, no puede haber un conteo de 7 a 2, por ejemplo: deberá ser de 2 a 7.

Sin embargo, hay maneras de emular estos comportamientos. Imagina que quieres un bucle que cuente de 1 a 10 de 2 en 2, de forma que el cuerpo del bucle sólo se ejecutará con valores pares de la variable de control. Como sabemos que dicha variable sólo se puede incrementar de 1 en 1, haríamos algo cómo lo siguiente:

@for $i from 1 through 10 {
    @if $i % 2 == 0{
        // Cuerpo del bucle
    }
}

Resuelto. El bucle realiza todas las iteraciones pero, gracias al condicional, el cuerpo del bucle sólo se ejecuta en las iteraciones pares.

Ahora veamos cómo hacer un bucle con una cuenta descendente:

@for $i from 1 through 10{
    $j: 11 - $i;
    // Cuerpo del bucle que emplea $j como si fuera la variable de control
    // Observa que creamos $j restando la variable de control del límite 
    // superior más 1, para que tome los valores de 10 a 1.
}

Otra manera de soslayar las limitaciones que acabamos de comentar la encontramos en el apartado que ves a continuación.

LA DIRECTIVA @while

Esta directiva nos permite, al igual que la instrucción homónima de otros lenguajes, crear bucles cuya ejecución dependa de una condición que no necesariamente tiene por qué estar supeditada al valor numérico de una variable de control. La sintaxis general de esta estructura es la siguiente:

@while condicion{
    // Cuerpo del bucle
}

Mientras la condición especificada se evalúe a true, se estará iterando en el bucle. Las iteraciones terminarán cuando la condición se evalúe a false.

ATENCIÓN. Este tipo de estructura tiene un riesgo inherente que, seguramente, ya conocerás de otros lenguajes: los bucles infinitos. Si la condición nunca se evalúa a false, nunca saldrás del bucle. Esto da lugar a que, al pretender transpilar a CSS, tu transpilador (gulp, ruby, prepros o el que sea que uses) genere un error que, en el mejor de los casos, abortará la transpilación y, en el peor, te bloqueará el proceso.

Que la condición no tenga por qué ser numérica no significa que no pueda serlo. De hecho, usar estos bucles con condiciones basadas en valores numéricos es la alternativa que comentábamos antes para solventar las limitaciones de @for. Imagina un bucle en el que quieres contar de 2 en 2, en lugar de hacerlo de 1 en 1. Vamos a hacer un bucle que cree unas clases basadas en un mapa, cómo hicimos anteriormente, pero sólo creando clases para los elementos pares del mapa, como ves en while_1.scss:

El código anterior se transpila a while_1.css, así:

Otro ejemplo sería el que nos permitiría hacer una cuenta descendente. Observa while_2.scss:

El código anterior se transpila a CSS así:

ATENCIÓN. Aunque uses los bucles @while con una condición numérica, esta directiva, al contrario que @for, no varía de forma automática el valor de la variable de control. Por lo tanto, dentro del cuerpo del bucle debes asegurarte de que se cambie su valor, programando la variación como ves en las líneas resaltadas en while_1.scss y while_2.scss. De lo contrario, entrarías, como te he comentado antes, en un bucle infinito.

CONCLUYENDO

En este artículo hemos aprendido a construir bucles que permiten generar mucho código CSS con muy pocas líneas de SASS, de una forma elegante y limpia. Los códigos necesarios para que experimentes los tienes en este enlace.

   

Deja un comentario