Wednesday, March 9, 2016

8 important Sass mixins must have in your toolbox

At their core, Sass mixins are blocks of code that you define once and can then re-use anywhere, if you are familiar with any programming language you can think of them as functions. A mixin can take multiple parameters and make calls to functions to in the end output CSS, and they are super useful when you want really clean and DRY code.
Some of the mixins below are already included in the Compass library, but since I prefer not to use Compass in my projects, I decided to write them myself.
So, here are the 8 mixins I think every developer should have in their toolbox.

1. Set a rem font size with pixel fallback

Rem is similar to the em value, but instead of being relative to the parent element it’s relative to the font-size set in the <html>.
It has all the benefits of em but you don’t get issues with e.g (compounding) since rem is only relative to the html element. The bad part is there’s no support for rem units in IE8 and below. But with this mixin we can create a fallback to pixels when rem isn’t supported.
@mixin font-size($font-size) {
 font-size: $font-size * 1px;
 font-size: $font-size / 10 * 1rem;
}

Usage

p {
  @include font-size(14px)
}

Output

p {
  font-size: 14px; //Will be overridden if browser supports rem
  font-size: 0.8rem;
}

2. Breakpoints

When Sass 3.2 was released some time ago, they made it possible to define names to our media queries, which makes the usage of them a lot cleaner. Instead of calling them @media (min-width: 600px) we can give them more semantic names like “breakpoint-large” or “breakpoint-a-really-large-computer-machine”.
@mixin bp-large {
  @media only screen and (max-width: 60em) {
    @content;
  }
}

@mixin bp-medium {
  @media only screen and (max-width: 40em) {
    @content;
  }
}

@mixin bp-small {
  @media only screen and (max-width: 30em) {
    @content;
  }
}

Usage

.sidebar {
  width: 60%;
  float: left;
  margin: 0 2% 0 0;
  @include bp-small {
    width: 100%;
    float: none;
    margin: 0;
  }
}

Output

.sidebar {
  width: 60%;
  float: left;
  margin: 0 2% 0 0;
  @media only screen and (max-width: 30){
    .sidebar{width: 100%; float: none; margin: 0;}
  }
}

3. SVG background images with PNG and retina fallback

This mixin depends on Modernizr and creates a bit more work for you when creating images for your site, but it’s really worth it in the end.
You need one .svg file, that will serve as the default background image. You’ll also need a regular .png that serves as a fallback for non-svg-supporting browsers. And last you need a twice as large .png as a second fallback to retina screens.
All in all you need this:
  • pattern.svg
  • pattern.png
  • pattern@2x.png
$image-path: '../img' !default;
$fallback-extension: 'png' !default;
$retina-suffix: '@2x';
@mixin background-image($name, $size:false){
    background-image: url(#{$image-path}/#{$name}.svg);
    @if($size){
        background-size: $size;
    }
    .no-svg &{
        background-image: url(#{$image-path}/#{$name}.#{$fallback-extension});

        @media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
          background-image: url(#{$image-path}/#{$name}#{$retina-suffix}.#{$fallback-extension});
        }
    }
}

Usage

body {
  @include background-image('pattern');
}

4. Animations and keyframes

Animations are always a pain to create with all the vendor prefixes and what not. But with the help of this mixin it will boil down to just a few lines of code.
@mixin keyframes($animation-name) {
    @-webkit-keyframes #{$animation-name} {
        @content;
    }
    @-moz-keyframes #{$animation-name} {
        @content;
    }  
    @-ms-keyframes #{$animation-name} {
        @content;
    }
    @-o-keyframes #{$animation-name} {
        @content;
    }  
    @keyframes #{$animation-name} {
        @content;
    }
}

@mixin animation($str) {
  -webkit-animation: #{$str};
  -moz-animation: #{$str};
  -ms-animation: #{$str};
  -o-animation: #{$str};
  animation: #{$str};      
}

Usage

@include keyframes(slide-down) {
  0% { opacity: 1; }
  90% { opacity: 0; }
}

.element {
  width: 100px;
  height: 100px;
  background: black;
  @include animation('slide-down 5s 3');
}

5. Transitions

As with animations, transitions also make your code quite bloated which can hurt the readability. But this is also solved by using a mixin for it.
@mixin transition($args...) {
  -webkit-transition: $args;
  -moz-transition: $args;
  -ms-transition: $args;
  -o-transition: $args;
  transition: $args;
}

Usage

a {
  color: gray;
  @include transition(color .3s ease);
  &:hover {
    color: black;
  }
}

6. Cross browser opacity

This mixin ensures cross browser opacity all the way down to Internet Explorer 5. Though if you have to optomize for IE5, you have a lot bigger problems than opacity, godspeed my friend.
@mixin opacity($opacity) {
  opacity: $opacity;
  $opacity-ie: $opacity * 100;
  filter: alpha(opacity=$opacity-ie); //IE8
}

Usage

.faded-text {
  @include opacity(0.8);
}

7. Clearfix

There’s a lot of different clearfix hacks out there on the web. This one is created by (Nicolas Gallagher) and I’ve found it to be the most solid one. Works in IE6 and up.
%clearfix {
  *zoom: 1;
  &:before, &:after {
    content: " ";
    display: table;
  }
  &:after {
    clear: both;
  }
}

Usage

.container-with-floated-children {
  @extend %clearfix;
}

8. Visually hide an element

When you hide an element with display: none, that prevents screen readers from reading it to the user. Sometimes that’s fine, but in other cases this will make the site hard to use for people with screen readers. Thus, we have to use another technique for hiding elements while at the same time make them accessible.
In this example, we are using the Sass placeholder selector since the output will always be the same, which enables us to reduce repetetive code in the output.
%visuallyhidden {
  margin: -1px;
  padding: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip: rect(0, 0, 0, 0);
  position: absolute;
}

Usage

<button class="mobile-navigation-trigger">
  <b class="visually-hidden">Open the navigation</b>
  <img src="img/mobile-navigation-icon.svg">
</button>
.visually-hidden {
  @extend %visuallyhidden;
}

Do you have any favorite mixins that you use a lot? Please post them in the comment field below!