ProgramandooIntentándolo

Tutorial Less: 8. Mixins con parámetros o mixins paramétricos

Logo less

En el anterior post vimos los mixins sin parámetros que nos permiten reutilizar fragmentos de código, pues con los mixins paramétricos podemos ir un paso más allá y podemos definir conjuntos de reglas reutilizables en las cuales podemos tener partes que pueden variar en función de los valores de los parámetros.

La forma de escribir los mixins no cambia, lo única diferencia son precisamente los parámetros que no son otro cosa que variables, con lo que vamos con el primer ejemplo de un mixin con un parámetro.


.bordeConEstilo(@radio) {
  border: 2px solid #147;
  border-radius: @radio;
}

.boton1 {
  width: 100px;
  height: 20px;
  .bordeConEstilo(5px);
}

.boton2 {
  width: 50px;
  height: 50px;
  .bordeConEstilo(50px);
}

En la definición del mixin hay una variable cuyo valor podemos utilizar en su interior y que nos permite utilizar las propiedades del mixin pero con la ventaja de poder hacer que los propiedades tomen valores personalizados y así nos ahorramos tener que hacer nuevos mixins o nuevas clases con las mismas propiedades y en las que solo cambian sus valores o alguno de sus valores.

En el caso concreto de este ejemplo básico tenemos un mixin en el que definimos un borde de forma fija y el radio que lo hacemos parametrizable para que lo podamos usar por ejemplo para hacer un botón ligeramente redondeado y otro redondo sin tener que hacer múltiples mixins.


.boton1 {
  width: 100px;
  height: 20px;
  border: 2px solid #147;
  border-radius: 5px;
}
.boton2 {
  width: 50px;
  height: 50px;
  border: 2px solid #147;
  border-radius: 50px;
}

Mixins con múltiples parámetros

Cuando un mixin tiene múltiples parámetros estos han de estar separados por “;” o por “,” aunque es recomendable usar el punto y coma por que la coma puede actuar también como separador para listas y por lo tanto se puede generar confusión si alguno de los parámetros recibe una lista.

Un ejemplo muy sencillo pero que demuestra la utilidad podría ser el uso de degradados al que acompañamos con un borde de uno de los colores del degradado.


.degradado(@angulo; @color1; @color2) {
  background: linear-gradient(unit(@angulo, deg), @color1, @color2);
  border: 2px solid @color1;
}

.boton-error {
  color: #fff;
  .degradado(180; #a00; #f00);
}

.boton-ok {
  color: #000;
  .degradado(-45; #060; #0a0);
}

Aunque el mixin siguen siendo 2 líneas como en el primer ejemplo (tampoco tiene sentido complicarlo más para entender cómo funciona) ya da una idea más real de la cantidad de líneas que nos pueden ahorrar y de lo importantes que pueden llegar a ser para tener unos estilos simples y organizados pero que a la vez nos permitan hacer casi cualquier cosa.


.boton-error {
  color: #fff;
  background: linear-gradient(180deg, #a00, #f00);
  border: 2px solid #a00;
}
.boton-ok {
  color: #000;
  background: linear-gradient(-45deg, #060, #0a0);
  border: 2px solid #060;
}

El orden de los parámetros en la definición del mixin y en las llamadas han de ser los mismos a no ser que se indique de forma explícita el nombre de los parámetros cuando se hace la llamada, por ejemplo para invertir el orden de color1 y color2 tendríamos que hacerlo así.


.boton-info {
  color: #fff;
  .degradado(@angulo: -45; @color2: #006; @color1: #00a);
}

.boton-info {
  color: #fff;
  background: linear-gradient(-45deg, #00a, #006);
  border: 2px solid #00a;
}

Aparte de para poder introducir los parámetros en un orden distinto al de la declaración también se puede utilizar simplemente para que quede más claro que representa cada valor.

Mixins con parámetros con valores por defecto

Puede que queramos que algunos de los parámetros no sean obligatorios y que tengan un valor por defecto para cuando no se rellenen. La forma de hacer esto es añadir el valor por defecto detrás del nombre del parámetro y separado por “:” justo como acabamos de ver para poder pasar los parámetros por su nombre si están desordenados, y precisamente uno de los motivos para que estén “desordenados” es que alguno de los parámetros tenga un valor por defecto y no se pase.


.degradado2(@angulo: 90; @color1; @color2: #fff) {
  background: linear-gradient(unit(@angulo, deg), @color1, @color2);
  border: 2px solid @color1;
}

.botonA {
  .degradado2(@color1: #147);
}

.botonB {
  .degradado2(@color1: #147; @color2: #000);
}

.botonC {
  .degradado2(180; #ccc; #222);
} 

Por lo tanto si una propiedad tiene un valor por defecto y no se pasa ese parámetro en la llamada del mixin se utiliza el valor por defecto y si si que se pasa pues el valor indicado sobrescribe al valor por defecto.


.botonA {
  background: linear-gradient(90deg, #147, #fff);
  border: 2px solid #147;
}
.botonB {
  background: linear-gradient(90deg, #147, #000);
  border: 2px solid #147;
}
.botonC {
  background: linear-gradient(180deg, #ccc, #222);
  border: 2px solid #ccc;
}

La variable @arguments y los “…” en los mixins

La variable @arguments contiene los valores de todas las propiedades del mixin por lo que puede ser útil cuando el conjunto de parámetros se pueden aplicar directamente a una propiedad como por ejemplo el borde.


.miBorde(@ancho; @estilo; @color) {
  border: @arguments;
}

.cuadro {
  width: 100px;
  height: 100px;
  .miBorde(5px; solid; blue);
} 

El resultado es el mismo que si hubiésemos puesto uno a uno los parámetros dentro del mixin.


.cuadro {
  width: 100px;
  height: 100px;
  border: 5px solid blue;
} 

También existe la posibilidad de que un mixin tenga un numero variable de argumentos, para este caso la propiedad si solo es una o la última si hay varias tiene que ir seguida de “…” y así contendrá todos los parámetros que superen el índice de esa variable.


.miBordeRedondeado(@radio; @borde...) {
  border-radius: @radio;
  border: @borde;
}

.cuadron {
  width: 100px;
  height: 100px;
  .miBordeRedondeado(5px; 1px; solid; blue);
}  

En este ejemplo como borde lleva los puntos suspensivos, la primera variable que pongamos se corresponderá con el radio y el resto de variables se guardaran dentro de @borde.


.cuadron {
  width: 100px;
  height: 100px;
  border-radius: 5px;
  border: 1px solid blue;
}  

Mixins aplicables por coincidencia de patrones

Y para terminar con los mixins paramétricos, vamos a ver que se puede hacer que se utilice un determinado mixin u otro dependiendo del valor de uno de sus parámetros, es decir, podemos hacer que se utilice un mixin determinado solo si el valor de sus parámetros coincide con el que esta fijado en el mixin.

Para esto el primer parámetro en lugar de ser una variable tiene que ser un valor fijo y cuando se llame al mixin si el primer parámetro coincide con ese valor entonces se utilizará ese mixin y si no coincide no se usará, es decir, son mixin condicionales al estilo de los switch-case de javaScipt por poner un ejemplo.

Vamos a ver un ejemplo para simular un switch con 2 valores y un valor por defecto, aunque el concepto de valor por defecto está un poco cogido con pinzas.


@tema: claro;
@colorFuenteClaro: #ee0;
@colorFuenteOscuro: #004;

.fondoSelectivo(@meDaIgual; @color) {
  background: @color;
  border: 2px solid @color;
  color: contrast(@color, @colorFuenteOscuro, @colorFuenteClaro);
}

.fondoSelectivo(claro; @color) {
  background: lighten(@color, 20%);
  border: 2px solid @color;
  color: contrast(lighten(@color, 20%), @colorFuenteOscuro, @colorFuenteClaro);
}

.fondoSelectivo(escalaGrises; @color) {
  background: greyscale(@color);
  border: 2px solid greyscale(@color);
  color: contrast(@color);
}

.contenedor {
  padding: 15px;
  .fondoSelectivo(@tema; #147);
}

.contenedorGris {
  padding: 15px;
  .fondoSelectivo(escalaGrises; #147);
}

.contenedorLibre {
  padding: 15px;
  .fondoSelectivo(vale; #147);
}  

Tenemos el mixin .fondoSelectivo que tiene 3 definiciones distintas todas ellas con 2 parámetros, con lo que habíamos visto hasta ahora aplicarían las 3 porque tienen el mismo número de parámetros y la selección del mixin se hace por número de parámetros (el nombre de las variables da igual, solo sirve para poner un orden distinto en la llamada), bueno en realidad por número de parámetros que se puedan pasar porque si tuviésemos otro mixin con el mismo nombre y 4 parámetros y dos de ellos opcionales también se aplicaría.

Pero aquí tenemos una pequeña gran diferencia claro y escalaGrises no tienen la @ por que no son variables, son el valor necesario para que se use el mixin, por lo tanto en este ejemplo en .contenedor se aplica el mixin con la opción claro, en contenedorGris la opción escalaGrises y el mixin con la variable @meDaIgual se aplica a los 3 porque como es una variable acepta cualquier valor.


.contenedor {
  padding: 15px;
  background: #147;
  background: #1e77d0;
  border: 2px solid #147;
  color: #ee0;
}
.contenedorGris {
  padding: 15px;
  background: #147;
  border: 2px solid #147;
  color: #ee0;
  background: #444444;
  border: 2px solid #444444;
  color: #ffffff;
}
.contenedorLibre {
  padding: 15px;
  background: #147;
  border: 2px solid #147;
  color: #ee0;
}  

En el CSS que genera hay propiedades repetidas porque aplican tanto el “mixin por defecto” como el que corresponde pero como el especifico esta detrás las sobrescribe y quedan los valores esperados, para ver los conceptos no está mal, pero no es lo más correcto.

En el próximo post seguiremos con los mixins condicionales que nos van a dar muchas más versatilidad al permitirnos aplicar los mixins en función de condiciones más complejas, y como siempre aquí tienes el enlace para descargar un archivo .less con todos los ejemplos.