Sass Mixins to Kickstart Your Project

Tweet

Mixins are great, aren’t they? They are like functions that output CSS. According to the Sass docs:

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. They can even take arguments which allows you to produce a wide variety of styles with very few mixins.

Mixins are really convenient, especially when working on a large project. How many times have you had to define width and height values in your last project? How many times have you Googled how to do a triangle in CSS? Or haven’t you ever wished there was a shorthand for top, right, bottom, left when using CSS positioning?

You can solve all those problems with mixins. Even better: you won’t have to write them since I’ve already done that for you. Here we go guys, a couple of Sass mixins to kickstart your projects!

Sizing Mixin

I bet you already know this one. I use it as a mixin 101 in all my projects: a size() mixin defining both the width and the height. First argument is the width, second one is the height. If height is omitted, it falls back to the width value.

@mixin size($width, $height: $width) {
      width: $width;
      height: $height;
}

Simple enough.

Example Usage

Sass:

.element {
  @include size(100%);
}

.other-element {
  @include size(100%, 1px);
}

CSS output:

.element {
  width: 100%;
  height: 100%;
}

.other-element {
  width: 100%;
  height: 1px;
}

Positioning Mixin

If there is one shorthand I really think CSS misses, it’s a shortcut for offsets: top, right, bottom and left. We have shorthands for everything: padding, margin, background, even text-decoration! But we still don’t have one for offsets… So I built my own.

It was inspired by Stylus’ syntax:

absolute: top 0 left 1em

Unfortunately, Sass doesn’t provide a transparent mixin feature so, at best, we can come up with something like this:

@include absolute(top 0 left 1em);

… which is not that bad, you have to admit. Obviously we’ll also have relative() and fixed() which work the same way.

I dedicated a whole blog post to the making of this mixin so I won’t get too deep into details here, but the main idea is to provide a list of values to the mixin. Whenever a keyword is found (top, right, bottom, left), the value directly after the keyword gets applied to it, as long as it is a valid value.

@mixin position($position, $args) {
  @each $o in top right bottom left {
        $i: index($args, $o);

    @if $i and $i + 1< = length($args) and type-of(nth($args, $i + 1)) == number  {
          #{$o}: nth($args, $i + 1);
    }
  }

  position: $position;
}

@mixin absolute($args) {
        @include position("absolute", $args);
}

@mixin fixed($args) {
        @include position("fixed", $args);
}

@mixin relative($args) {
        @include position("relative", $args);
}

Example Usage

Sass:

.element {
  @include absolute(top 0 left 1em);
}

.other-element {
  @include fixed(top 1em left "WAT? A STRING?!" right 10% bottom)
}

CSS output:

.element {
  position: absolute;
  top: 0;
  left: 1em;
}

.other-element {
  position: fixed;
  top: 1em;
  right: 10%;
}

Vendor Prefix Mixin

You know how you have to prefix some properties with -webkit- or -moz- (among other prefixes) for them to work across browsers because they are non-standard properties? Then you also know how annoying that can be. This is precisely the type of thinking Compass and Bourbon try to fix by providing a collection of mixins dealing with prefixes for you (e.g. @include box-sizing()).

I have been using Compass for long now but I have recently decided to ditch it. The main reason is I wasn’t using it enough to keep it in projects; in the end, this means faster compilation times. That being said, I found myself in need of vendor prefix mixins. So I built one (and updated it when moving to Sass 3.3).

Sass 3.2 Version

The idea is very simple. The first argument is the property. The second argument is the value for that property. Third and optional argument is the list of prefixes to use. Default value dumps all prefixes.

@mixin prefix($property, $value, $vendors: webkit moz ms o) {
      @if $vendors {
        @each $vendor in $vendors {
          #{"-" + $vendor + "-" + $property}: #{$value};
        }
      }
      #{$property}: #{$value};
}

Example Usage

Sass:

.element {
  @include prefix(transform, rotate(42deg), webkit ms);
}

Ouput:

.element {
  -webkit-transform: rotate(42deg);
  -ms-transform: rotate(42deg);
  transform: rotate(42deg);
}

Sass 3.3 Version

My Sass 3.3 version is even better because it allows you to prefix multiple properties at once, and to have a nicer syntax. Basically, instead of having two distinct arguments for property and value, you have only one: A map of declarations. Keys are properties, values are values.

@mixin prefix($map, $vendors: webkit moz ms o) {
  @each $prop, $value in $map {
        @if $vendors {
          @each $vendor in $vendors {
            #{"-" + $vendor + "-" + $prop}: #{$value};
          }
        }
        // Dump regular property anyway
        #{$prop}: #{$value};
  }
}

Example Usage

Sass:

.element {
  @include prefix((transform: translate(-50%, -50%)), webkit ms);
}

.other-element {
  @include prefix((
    column-count: 3,
    column-gap: 1em,
    column-rule: 1px solid silver,
    column-width: 20em
  )), webkit moz);
}

CSS output:

.element {
  -webkit-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
}

.other-element {
  -webkit-column-count: 3;
  -moz-column-count: 3;
  column-count: 3;
  -webkit-column-gap: 1em;
  -moz-column-gap: 1em;
  column-gap: 1em;
  -webkit-column-rule: 1px solid silver;
  -moz-column-rule: 1px solid silver;
  column-rule: 1px solid silver;
  -webkit-column-width: 20em;
  -moz-column-width: 20em;
  column-width: 20em;
}

Pushing Things Further

What’s cool with this mixin is it can easily be used in other mixins to avoid having to type prefix() and the vendor prefixes every time. Think of something like this:

@mixin transform($value) {
      @include prefix(transform, $value, webkit ms);
}

@mixin column-count($value) {
      @include prefix(column-count, $value, webkit moz);
}

And here’s the example usage:

.element {
  @include transform(rotate(42deg));
}

And the CSS output:

.element {
  -webkit-transform: rotate(42deg);
  -ms-transform: rotate(42deg);
  transform: rotate(42deg);
}

Opposite Direction Mixin

If you’re a user of Compass, you may be familiar with the opposite-direction function (yes, this one is a function and not a mixin, but whatever). The one from Compass is built in Ruby but it’s quite easy to make a Sass one. The one I made relies on Sass 3.3 but it can easily be tweaked to be available to Sass 3.2.

What I like in my function is it allows you to pass a list of directions, so that you get bottom left from opposite-direction(top right). It can be useful when dealing with background-position, for instance.

@function opposite-direction($directions) {
      $opposite-directions: ();
      $direction-map: (
    'top': 'bottom',
    'right': 'left',
    'bottom': 'top',
    'left': 'right',
    'ltr': 'rtl',
    'rtl': 'ltr'
  );

  @each $direction in $directions {
    $opposite-direction: map-get($direction-map, $direction);
        @if $opposite-direction != null { 
      $opposite-directions: append($opposite-directions, #{$opposite-direction});
    }
    @else {
      @warn "No opposite direction can be found for `#{$direction}`.";
    }
  }

  @return $opposite-directions;
}

Example Usage

$direction: opposite-direction(top); 
// bottom

$other-direction: opposite-direction(bottom left);
// top right

Breakpoint Handler Mixin

If you’ve ever had to do some responsive design, you know working with several different media queries can be hard. It’s often a good idea to store the various breakpoints in variables so they can easily be retrieved without having to be typed all over again every single time.

If you want to take it a step further, you might want to name your breakpoints — which is a very good idea if you want my opinion. This basically means a media query is mapped to a name so you only have to give your breakpoint handler mixin a name to make it dump a media query. Many smart developers including Chris Coyier have made the idea quite popular.

Now if you want to go even further, you can store all those breakpoints in a global map, then make the mixin retrieve the breakpoint based on the name you pass it. Please consider the following code:

$breakpoints: (
  'tiny':   ( max-width:  767px ),
  'small':  ( min-width:  768px ),
  'medium': ( min-width:  992px ),
  'large':  ( min-width: 1200px ),
  'custom': ( min-height:  40em )
);

@mixin breakpoint($name) {
      @if map-has-key($breakpoints, $name) {
        @media #{inspect(map-get($breakpoints, $name))} {
      @content;
    }
  }
  @else {
    @warn "Couldn't find a breakpoint named `#{$name}`.";
  }
}

If the string passed to the breakpoint mixin matches a key in the $breakpoints map, the mixin opens a @media directive, using the inspect function (from Sass 3.3 as well) to literally dump a map. When doing inspect((key: value)), (key: value) gets printed as is in the stylesheet.

If the string doesn’t match an existing breakpoint, then the user gets warned through the @warn directive, printing an error message in his console.

Example Usage

Sass:

.element {
  color: red;

  @include breakpoint(medium) {
    color: blue;
  }
}

CSS output:

.element {
  color: red;
}

@media (min-width: 992px) {
  .element {
    color: blue;
  }
}

Final Thoughts

I think that’s a good start! Those tools should help get rid of some time-consuming tasks when writing the CSS for your next project. Be sure to use them, tweak them and give your feedback!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.12snaps.com/ Paweł Grzybek

    WOW. The last one is a much cleaner version well know mixin what I use in every single project. Thanks Hugo!

  • callmenick1

    The breakpoint mixin is amazing.,,by far my favourite on this list.

  • http://hugogiraudel.com/ Hugo Giraudel

    I’m sure nobody ever forced you to use any tool. :)

  • http://hugogiraudel.com/ Hugo Giraudel

    Yeah… SitePoint is having some issues with its code editor. I can’t do much about it unfortunately but I’ll tell them to have a look.

  • http://josephrex.me/ Joseph Rex

    Using autoprefixer makes the vendor prefix mixin irrelevant. I have it post-processing my CSS from config.rb