Without question, one of the most powerful and valuable features of Sass is the ability to package up existing code into reusable chunks of code called mixins.
Mixins are like macros
Mixins are the Sass equivalent of macros in other programming languages. If you’ve programmed before you could think of them as functions, procedures, or methods, but they aren’t technically any of these concepts because their function is to generate code at compile time not execute code at run time.
How Mixins Work
The Compass project is chock full of mixins to make your life easier. From CSS3, to typography, to layout, to image manipulation, Compass makes it easy to write bullet-proof CSS that works across browsers. We like to think of Compass as the standard library for Sass.
The CSS3 support in Compass is perhaps the most rocking aspect of the project. Compass provides an assortment of CSS3 mixins that make it easy to take advantage of these new features in a way that works across browsers.
For instance. The border-radius mixin lets you use the new border-radius
attribute in a succinct way:
a.button {
background: black;
color: white;
padding: 10px 20px;
@include border-radius(5px);
}
This would output:
a.button {
background: black;
color: white;
padding: 10px 20px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
-khtml-border-radius: 5px;
border-radius: 5px;
}
Looking at the output you can see that the border-radius
mixin outputs six lines of code. These six lines allow you to use border-radius across all of the modern web browsers. (The cool part is that if you wrote this code on your own, you probably would not have included support for Opera (-o) or Konquerer (-khtml), but Compass gives you all this for free!)
Above, I used the @include
directive to tell Sass that I wanted to call out to a mixin. This was followed by the name of the mixin, border-radius
. Followed by parentheses enclosing the arguments to pass the mixin. The border-radius
mixin only has one argument. In this case 5px
is passed as the value of the first argument.
Writing Your Own
Let’s look at the source for the border-radius mixin above. For the purpose of illustration I’m going to show you a simplified version of the mixin. The actual version from Compass is a bit more complicated, but this will give you a good idea of how to write your own:
@mixin border-radius($radius) {
-moz-border-radius: $radius;
-webkit-border-radius: $radius;
-ms-border-radius: $radius;
border-radius: $radius;
}
The declaration begins with the directive @mixin
and is followed by the name of the mixin. In this case border-radius
. The name of the mixin can contain any combination of alpha and numeric characters without spaces. Then comes the list of arguments that the mixin accepts enclosed in parentheses ( ... )
. The mixin above only has one argument $radius
. Multiple arguments can be used as long as they are separated by commas.
Next comes the definition of the mixin enclosed in braces { ... }
. The definition of the mixin can contain any combination of CSS attributes. You can even declare additional rules (with selectors) that will be mixed into your CSS along with the attributes.
In this case, the border-radius
mixin includes a series of CSS attributes to set the value of the border-radius
attribute for all of the major browsers who have implemented it with browser-specific prefixes and the final border-radius
attribute to future-proof the attribute because it has been officially accepted as part of the CSS3 spec.
The $radius
argument, or variable is used to set the value of each of the CSS attributes. Using this technique you can pass one value to the mixin and it will be repeated four times in the output. This reduces the likelihood that you will miss-type the value for one or more of the browser-specific attributes (if you were to type this out by hand instead of using the mixin) and also saves a lot of typing.
Default Arguments
You could improve this mixin by adding a default value for the $radius
argument, like this:
@mixin border-radius($radius: 5px) {
...
}
This makes the $radius
argument optional. So you can call the mixin without it like this:
@include border-radius;
Which would output the attributes with the default value in the argument list of the declaration. In this case 5px
because that’s what we declared above.
Another trick that can be quite useful is to declare a variable beforehand and use that as the default value for the mixin:
$default-border-radius: 5px !default;
@mixin border-radius($radius: $default-border-radius) {
...
}
This is especially useful for code that you share between projects. Set the default by modifying the global variable, and override the value as needed.
Keyword Arguments
One final mixin feature that is new as of Sass 3.1 is keyword arguments. Keyword arguments are especially useful when a mixin accepts multiple arguments. If the arguments are defaulted, you can use the name of the argument to set the specific value for an argument, without passing the values of the other arguments.
Used with @if
conditionals, we can make an even better version of the border-radius
mixin:
@mixin border-radius($radius: 5px, $moz: true, $webkit: true, $ms: true) {
@if $moz { -moz-border-radius: $radius; }
@if $webkit { -webkit-border-radius: $radius; }
@if $ms { -ms-border-radius: $radius; }
border-radius: $radius;
}
The code above conditionally outputs the code for Firefox, Safari, and Internet Explorer based on the values of $moz
, $webkit
, and $ms
, respectively. Since all of the arguments have default values, you could turn off support for just Internet Explorer by calling the mixin like this:
@include border-radius($ms: false);
This is much simpler than calling the mixin with each of the arguments without names:
@include border-radius(5px, true, true, true);
With keyword arguments, you don’t even have to call out to the mixin with the arguments in the same order that they were declared:
@include border-radius($ms: false, $radius: 10px);
Conclusion
That about wraps up this overview of Sass mixins. To get a better idea of how you can use them in your code, I recommend taking a look at the source code for a mature Sass project like Compass which includes over 200 mixins you can use to learn a lot of great techniques from. Also, the Compass docs actually include “View Source” links that make it easy to check out the code for any mixin to see what it does. You can start by checking out the actual implementation of border-radius.