CSS animations provide quick and easy means for adding a bit of pizzazz to your interface. They are great when you need to create complex animations over time using their keyframes property. For the most part animations do their intended job well. But over the past year or so I have noticed a couple of nasty side effects that can make them very frustrating to work with. In this post I will demonstrate some of the properties shortcomings and how they can be overcome with transitions and a little JavaScript.

Reversing the animation

The first issue I discovered whilst working with animations is that they animate in but will not animate back out (reverse their transformed properties). The example below shows an element animating into view and as we remove the class with the animation set, the element snaps immediately back to its initial state.


Transitions will smoothly reverse most properties that have changed between the initial and final state.

Multiple animations and transitions

In some cases you may find yourself wanting to apply a transition to an element that also has the animation property set. For whatever reason this produces some pretty gnarly results, with elements flickering and jumping around the page. Hover over the face in the following example to see the effect.

Not cool!

With transitions you can remove and stack transitions as you so choose and they will behave fairly predictably. Here is an example of the same effect as previous, only with transitions this time.

On scroll animations

It is fairly trendy to animate elements in as they appear in the viewport (all the hipster kids are doing it). Many use the popular waypoints library to facilitate this technique. To produce this effect with animations we must first apply display: none; along with an animation declaration to the initial state of an element. As the element rises up into the viewport we remove (by adding a new class in JavaScript) the display: none; property and the element will animate into view, which looks great, but our page is now afflicted with a new issue.

When we apply display: none; to an element, we are (physically speaking) taking it out of the our DOM. This means the element’s dimensions are no longer respected, causing some ugly reshuffling and jolting of the surrounding and proceeding elements. There are ways to get around this but most involve non-semantic wrappers or setting fixed heights on affected elements. But that’s no fun for anyone and can cause more drama down the track.


Transitions provide a distinct advantage in this scenario as we don’t rely on the display: none; property to animate our element allowing for much smoother and predictable animations.

Muuuuch better!

That wraps up my recent findings with animations and my methods to get around some of their shortcomings. I am interested to hear what issues you may have come across, or if you have experienced any of the above and what methods you use to get around them.

I have poked a lot of holes in animations in this post but don't be discouraged and abandon them completely. Whilst there are a number undesirable side effects with animations they still have their place in your stylesheets. There is no real substitute when you require more complex keyframes for your animation (other than 0% and 100% or from and to).


I have developed this mixing that I have been using in my latest build and thought I would share it with those of you who made it this far.

The mixin takes a couple of parameters and fades and element into the view port from a specified direction and distance.

  @mixin appear($duration: show, $shift: 0, $from: left) {
    // Determine if the element needs to move negatively or positively
    $direction: if($from == left or ($from == top), "-", "");
    // Determine the axis we need to manipulate
    $axis: if($from == left or ($from == right), X, Y);
    // Only set a transition if the duration is set, this prevents duplication of the property when the applied the second time
    @if $duration {
      @include transition(all #{$duration} $ease-out-quad);
    // Hide the element if duration is set, show if it isn’t
    opacity: if($duration != show, 0, 1);
    // Apply the transformation to the required axis, in the specified direction for length of the distance we specified
    @include transform(translate3d(if($axis == X, #{$direction}#{$shift}, 0), if($axis == Y, #{$direction}#{$shift}, 0), 0));

There is nothing terribly complicated going on in this mixin and the commenting should make it fairly simple to follow.


Apply the mixin to the initial state of an object with the following (change the parameters to suit your needs):

@mixin appear(1s, 200px, right);

Apply the mixin to the final state of the object but pass no parameters. The mixin will reverse the passed parameters back to 0 - their final state before the initial transformations.

@mixin appear();

Interrogate the following pen to get a better understanding:

I will be refining and adding extra parameters to this mixin as I work with it more and would appreciate your input on how it can be improved. Once I am happy with the state of this one I will be making a few more mixins like it and developing a little of library of commonly used transitions.

1,719 3 12