Sass, el manual oficial

Capítulo 9. Directivas mixin

Los mixins permiten definir estilos reutilizables en toda la hoja de estilos sin tener que recurrir a clases CSS no semánticas del tipo .float-left. Los mixins también pueden contener reglas CSS y cualquier otro elemento definido por Sass. Los mixins incluso admiten el uso de argumentos, como si fueran funciones, para poder modificar su comportamiento y ofrecer así una mayor flexibilidad.

9.1. Definiendo mixins con la directiva @mixin

Los mixins se definen con la directiva @mixin seguida del nombre del mixin (y opcionalmente una lista de argumentos) y seguida por el bloque de contenidos que definen los estilos del mixin. El siguiente ejemplo define un mixin sin argumentos llamado large-text:

@mixin large-text {
  font: {
    family: Arial;
    size: 20px;
    weight: bold;
  }
  color: #ff0000;
}

Además de estilos, los mixins también pueden contener selectores, incluso con referencias al selector padre. Ejemplo:

@mixin clearfix {
  display: inline-block;
  &:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
  }
  * html & { height: 1px }
}

9.2. Incluyendo mixins con @include

Los mixins se incluyen en las hojas de estilos mediante la directiva @include seguida del nombre del mixin y opcionalmente por una lista de argumentos. El resultado es que todos los estilos definidos por el mixin se incluyen en el mismo punto en el que se llama al mixin. Ejemplo:

.page-title {
  @include large-text;
  padding: 4px;
  margin-top: 10px;
}

El código Sass anterior se compila de la siguiente manera:

.page-title {
  font-family: Arial;
  font-size: 20px;
  font-weight: bold;
  color: #ff0000;
  padding: 4px;
  margin-top: 10px;
}

Los mixins también se pueden incluir en el nivel jerárquico superior de la hoja de estilos, es decir, fuera de cualquier selector o regla. Obviamente, estos mixins no pueden incluir ninguna referencia al selector padre, ya que se produciría un error. Ejemplo:

@mixin silly-links {
  a {
    color: blue;
    background-color: red;
  }
}

@include silly-links;

El código Sass anterior se compila de la siguiente manera:

a {
  color: blue;
  background-color: red;
}

Los mixins también pueden incluir en su interior otros mixins. Ejemplo:

@mixin compound {
  @include highlighted-background;
  @include header-text;
}

@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }

Aunque no es muy habitual, los mixins también pueden incluirse a sí mismos de manera recursiva. En las versiones de Sass anteriores a la 3.3 esta recursividad no estaba permitida.

9.3. Argumentos

Los argumentos de los mixins pueden estar formados por cualquier expresión SassScript. Estos argumentos están disponibles en el interior del mixin en forma de variables.

Cuando se define un mixin, los argumentos se definen como una serie de variables separadas por comas, y todo ello encerrado entre paréntesis. Después, cuando se utiliza un mixin deben pasarse los valores de los argumentos en ese mismo orden. Ejemplo:

@mixin sexy-border($color, $width) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}

p { @include sexy-border(blue, 1in); }

El código Sass anterior se compila de la siguiente manera:

p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed;
}

Los mixins también pueden especificar valores por defecto para sus argumentos. De esta manera, si al llamar a un mixin no se pasa el valor de ese argumento, se utiliza en su lugar el valor por defecto. Ejemplo:

@mixin sexy-border($color, $width: 1in) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}
p { @include sexy-border(blue); }
h1 { @include sexy-border(blue, 2in); }

El código Sass anterior se compila de la siguiente manera:

p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed;
}

h1 {
  border-color: blue;
  border-width: 2in;
  border-style: dashed;
}

9.3.1. Argumentos con nombre

Cuando se utiliza un mixin también es posible indicar el nombre de sus argumentos:

p { @include sexy-border($color: blue); }
h1 { @include sexy-border($color: blue, $width: 2in); }

Aunque esta sintaxis es menos concisa que la anterior, hace que las hojas de estilos sean más fáciles de leer. Además permite que los mixins tengan interfaces más flexibles y fáciles de usar, aún cuando incluyan muchos argumentos.

Los argumentos con nombre se pueden pasar en cualquier orden y puedes omitir los que tienen un valor por defecto. Además, como los argumentos con nombre en realidad son nombres de variables, puedes utilizar indistintamente guiones medios y bajos.

9.3.2. Argumentos variables

En ocasiones es necesario que un mixin acepte un número indeterminado de argumentos. Si por ejemplo tienes un mixin que añade sombras a los elementos HTML, es preciso que ese mixin acepte cualquier número de sombras como argumentos. Por eso Sass soporta la creación de mixins con un número variable de argumentos.

Para indicar que un mixin tiene un número variable de argumentos, después del último argumento se añaden tres puntos (...). Esto hará que todos los argumentos sobrantes se guarden como una lista en ese último argumento. Ejemplo:

@mixin box-shadow($shadows...) {
  -moz-box-shadow: $shadows;
  -webkit-box-shadow: $shadows;
  box-shadow: $shadows;
}

.shadows {
  @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}

El código Sass anterior se compila de la siguiente manera:

.shadows {
  -moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  -webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
}

Los argumentos variables también contienen todos los argumentos con nombre pasados al mixin o función. Puedes acceder a ellos mediante la función keywords($args), que devuelve un mapa de cadenas de texto en las que el nombre de la variable no contiene el carácter $.

Los argumentos variables también se pueden utilizar cuando se llama a un mixin. Utilizando la misma sintaxis de los tres puntos (...) puedes expandir una lista de valores para pasar cada elemento de la lista como si fuera un argumento. Cuando esta sintaxis se utiliza con mapas, cada par clave: valor se transforma en un argumento con el nombre clave. Ejemplo:

@mixin colors($text, $background, $border) {
  color: $text;
  background-color: $background;
  border-color: $border;
}

$values: #ff0000, #00ff00, #0000ff;
.primary {
  @include colors($values...);
}

$value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
.secondary {
  @include colors($value-map...);
}

El código Sass anterior se compila de la siguiente manera:

.primary {
  color: #ff0000;
  background-color: #00ff00;
  border-color: #0000ff;
}

.secondary {
  color: #0000ff;
  background-color: #ff0000;
  border-color: #00ff00;
}

También es posible pasar una lista de argumentos y un mapa siempre que la lista se pase primero, como por ejemplo: @include colors($values..., $map...).

Los argumentos variables pueden servir por ejemplo para crear un mixin que modifique otro mixin existente añadiendo nuevos estilos. Ejemplo:

@mixin wrapped-stylish-mixin($args...) {
  font-weight: bold;
  @include stylish-mixin($args...);
}

.stylish {
  // El argumento $width se pasa con nombre al mixin "stylish-mixin"
  @include wrapped-stylish-mixin(#00ff00, $width: 100px);
}

9.4. Pasando bloques de contenidos a los mixins

A los mixins también se les puede pasar un bloque entero de reglas CSS. Este contenido se incluirá en el lugar donde el mixin haya definido la directiva @content. Gracias a esta característica es posible abstraer ciertas partes de la definición de los selectores y directivas. Ejemplo:

@mixin apply-to-ie6-only {
  * html {
    @content;
  }
}
@include apply-to-ie6-only {
  #logo {
    background-image: url(/logo.gif);
  }
}

El código Sass anterior se compila de la siguiente manera:

* html #logo {
  background-image: url(/logo.gif);
}

Estos mixins también se pueden definir mediante los siguientes atajos:

=apply-to-ie6-only
  * html
    @content

+apply-to-ie6-only
  #logo
    background-image: url(/logo.gif)

Nota Cuando se incluye la directiva @content más de una vez o se incluye dentro de un bucle, los contenidos se repiten para cada aparición de @content.

9.4.1. Contenxto variables y bloques de contenidos

Los bloques de contenidos pasados a los mixins se evalúan en el contexto en el que están definidos, no en el contexto del mixin. Esto significa que los bloques de contenidos no pueden utilizar las variables locales definidas en el mixin. Ejemplo:

$color: white;
@mixin colors($color: blue) {
  background-color: $color;
  @content;
  border-color: $color;
}
.colors {
  @include colors { color: $color; }
}

El código Sass anterior se compila de la siguiente manera:

.colors {
  background-color: blue;
  color: white;
  border-color: blue;
}

De esta forma, las variables que se utilizan en los bloques que se pasan a los mixins siempre hacen referencia a las variables definidas alrededor de ese bloque o directamente en el nivel jerárquico superior de la hoja de estilos. Ejemplo:

#sidebar {
  $sidebar-width: 300px;
  width: $sidebar-width;
  @include smartphone {
    width: $sidebar-width / 3;
  }
}