Skip to main content

The FreddyBushBoy SASS/Compass mixin building handbook

Sass Compass mixin creation

There's a lot to cover here so I'll try keep this to the point: mixins are freakin' awesome.

I'm assuming you already know what they are, but the SASS Documentation describes them like so:

Mixins allow you to define styles that can be re-used throughout the stylesheet without needing to resort to non-semantic classes like .float-left. Mixins can also contain full CSS rules, and anything else allowed elsewhere in a Sass document.

Clever use of mixins and extends is the one of the best ways to get the most of of SASS. This is a list I have compiled of good-to-know tips for building your own mixins - something I heartily encourage.

Of course, a lot of these tips aren't specific to building mixins, just general SASS functionality, but they come in especially useful in a mixin-type scenario such as building a mixin or admiring a mixin.

This article contains 44 mentions of the word mixin.

Contents

Mixins in your mixins

Yo Dawg, I heard you like mixins. But seriously now.. Starting off simply: you should definitely put mixins in your mixins, and for the sake of readability, put them at the top - before regular properties.

Extends too, get them in there for sure. Making good use of extends and placeholder classes saves on repetition, something I have banged on about before.

SCSS:

@mixin super-fancy-button {
  @extend %button;
  @include inline-block;
  @include border-radius(5px);
  color: white;
  background: red;
}

But more broadly speaking I actually mean: don't forget that Compass comes with loads of mixins. You will not only want to use many of these mixins within yours, but its always worth checking that what you are trying to do isn't already done in Compass.

Any fancy CSS3 property with vendor prefixes and stuff, Compass is bound to have a mixin for it - best to check.

Mixin arguments

Mixins can take arguments. Adding arguments allow you to produce a wide variety of styles with very few mixins. Remember that you can provide defaults for these arguments, ignoring them when not needed.

SCSS:

@mixin set-color($color: white, $bg: transparent) {
  background: $bg;
  color: $color;
}
.my-element {
  @include set-color(#333); // Provide a custom value for $color.
}
.my-other-element {
  @include set-color; // Provide nothing, get the defaults.
}

You can skip arguments with defaults by passing named arguments, for example: @include set-color($bg: blue); Arguments without defaults cannot be omitted.

Referencing parent selectors

So this is incredibly useful, one of SASS's best bits in my opinion. While not specific to mixin building by any means, it is something you will be using in your mixins often. In the context of mixin building, the "parent selector" is simply the CSS selector(s) you are applying the mixin to. You can reference the parent selector using the & character:

SCSS:

@mixin my-cool-mixin {
  color: black;
  &:hover,
  &.active {
    color: red;
    text-decoration: underline;
  }
  html.no-js & {
    color: green;
  }
}
.my-element {
  @include my-cool-mixin;
}

Outputs the following CSS:

.my-element {
  color: black;
}
.my-element:hover,
.my-element.active {
  color: red;
  text-decoration: underline;
}
html.no-js .my-element {
  color: green;
}

As you can see, you can explicitly specify where the parent selector should be inserted using the & character. This is really flexible given where you put it. Above we are referencing:

  • The parent selector's pseudo-class :hover
  • The parent selector when it also has the active class
  • And the parent selector when the html element containing it has the no-js class.

This is particularly useful when using a feature detection library such as Modernizr.

Passing content blocks to a mixin

So the idea here is that you can pass a block of styles to the mixin for placement within the styles defined in the mixin. This sounds more confusing than it is really - let's just look at an example, using a simple media query to target hdpi screens only:

SCSS:

@mixin hdpi-screens-only {
  @media (-webkit-min-device-pixel-ratio:1.5), (min-resolution:144dpi) {
    @content; // This is where styles passed to the mixin will go.
  }
}
.my-element {
  background-image: image-url("logo.png");
  @include hdpi-screens-only {  
    background-image: image-url("logo-x2.png");
    background-size: 100% auto;
  }
}

Outputs the following CSS:

.my-element {
  background-image: url('../images/logo.png');
}
@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
  .my-element {
    background-image: url('../images/logo-x2.png');
    background-size: 100% auto;
  }
}

Control directives

SASS supports some basic control directives: @if, @for, @each, and @while. Needless to say these come in really handy within mixins. They're quite a big subject though so this will have to be rather cursory - see the SASS Documentation on them for more information. Below is a quick example of probably the most common one - @if:

SCSS:

@mixin color-from-type($type) {
  @if $type == foo {
    color: red;
  } 
  @else if $type == bar {
    color: green;
  } 
  @else {
    color: black;
  }
}

Variable interpolation

Ordinarily you can't use variables as selectors and property names in SASS, but by using #{} interpolation syntax, you can! This comes in especially handy for mixins. See this example from my post on the CSS padding trick:

SCSS:

@mixin pad-ratio($x, $y, $selector: img) {
  position: relative;
  padding: 0 0 percentage($y/$x) 0;
  height: 0;
  #{$selector} {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
}

Helpful SASS/Compass functions

It helps to familiarise yourself with some of SASS and Compass's more useful functions - make use of them and you will wind up with more concise and efficient mixins. You can see the full list here but here's a few notables off the top of my head:

lighten($color, $amount) ​and darken($color, $amount)

I use these all the time - really handy for hover states and so on. As you might imagine, they give you a lighter or darker version of a given color, by however much you like. Takes a color and a number between 0% and 100%.

Example: color: lighten(#800, 20%);

complement($color)

I find this to be more useful when just prototyping or messing around really, but it's pretty sweet. If you give this function a color it will return a complementary one.

Example: $alt-color: complement($main-color);

image-url($path, [$only-path], [$cache-buster])

Really great function. Generates the path to an image relative to the project's images directory (set in config.rb). I use this all the time for backgrounds - by default it even wraps the path in url(), so its perfect really.

Example: background-image: image-url("logo.png");

​image-height($image) and image-width($image)

Returns the width or height of an image - the image being relative to the project images directory, same as above. I have used these a surprising amount actually - for generating background-size for instance.

Example: ​@include background-size(image-width("logo.png") image-height("logo.png"));

percentage($number)

Another excellent one, useful for lots of stuff, especially creating layouts - it keeps ugly things like width: 33.333333% out of my SCSS files and in my CSS files where they belong. You give this function a number, can be a decimal, a fraction, whatever, and it returns it as a percentage.

Example: width: percentage(1/3);

ceil($number) and floor($number)

Round a number to the next whole number up or down, respectively. Can even take (and retain) values like px and em. Useful but not exciting.

Example: padding-top: ceil(10.4px);

 

Well that's all for now! It's already a lot to take in but if there's anything you think I have missed please let me know in the comments!