Quick Fix: Sass Mixins for CSS Keyframe Animations

CSS Keyframe animations are awesome! I love the power and flexibility that using them gives me, especially when compared to the relatively simple nature of CSS transitions. With this power comes a problem. Even simple animations require a HUGE amount of CSS to make them cross-browser compatible. A simple move on the page requires this code:

.object-to-animate {
  -webkit-animation: move-the-object .5s 1;
  -moz-animation:    move-the-object .5s 1;
  -o-animation:      move-the-object .5s 1;
  animation:         move-the-object .5s 1;
}

@-webkit-keyframes move-the-object {
  0%   { left: 100px; }
  100% { left: 200px; }
}
@-moz-keyframes move-the-object {
  0%   { left: 100px; }
  100% { left: 200px; }
}
@-o-keyframes move-the-object {
  0%   { left: 100px; }
  100% { left: 200px; }
}
@keyframes move-the-object {
  0%   { left: 100px; }
  100% { left: 200px; }
}

Copying and pasting is overly difficult, but what happens if you now want to change the animation to end at left: 300px? And what if you have 30 animations? The complexity of your animation suite increases quickly, but there’s an easy solution to this problem.

Keyframe Animation Sass Mixins to the Rescue!

As with all things CSS, I’m convinced Sass makes generating keyframe animation code so much easier. Two simple mixins makes your life much easier, and your code much cleaner and more maintainable.

@mixin animation($animate...) {
    $max: length($animate);
    $animations: '';

    @for $i from 1 through $max {
        $animations: #{$animations + nth($animate, $i)};

        @if $i < $max {
            $animations: #{$animations + ", "};
        }
    }
    -webkit-animation: $animations;
    -moz-animation:    $animations;
    -o-animation:      $animations;
    animation:         $animations;
}

@mixin keyframes($animationName) {
    @-webkit-keyframes #{$animationName} {
        @content;
    }
    @-moz-keyframes #{$animationName} {
        @content;
    }
    @-o-keyframes #{$animationName} {
        @content;
    }
    @keyframes #{$animationName} {
        @content;
    }
}

Using the mixins looks like this:

@include keyframes(move-the-object) {
  0%   { left: 100px; }
  100% { left: 200px; }
}

.object-to-animate {
  @include animation('move-the-object .5s 1', 'move-the-object-again .5s 1 .5s');
} 

The mixin allows for chaining of animations and as many keyframes as you'd care to use. It's a simple syntax that is very readable and maintainable for the long-term.

What other mixins are you using that make your life easier?