Integralist
Integralist

Reputation: 2211

How can I convert this CSS3 animation into a Sass mixin?

I have the following animation code...

.a {
    background: url(../Images/experience-1.jpg) center center no-repeat red;
    z-index: 7;

    -webkit-animation-delay: 3s;
    -webkit-animation-duration: 5s;
    -webkit-animation-name: fadeout;
    -webkit-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -moz-animation-delay: 3s;
    -moz-animation-duration: 5s;
    -moz-animation-name: fadeout;
    -moz-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -o-animation-delay: 3s;
    -o-animation-duration: 5s;
    -o-animation-name: fadeout;
    -o-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    animation-delay: 3s;
    animation-duration: 5s;
    animation-name: fadeout;
    animation-fill-mode: forwards; /* this prevents the animation from restarting! */
}

.b {
    background: url(../Images/experience-2.jpg) center center no-repeat yellow;
    z-index: 6;

    -webkit-animation-delay: 18s;
    -webkit-animation-duration: 5s;
    -webkit-animation-name: fadeout;
    -webkit-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -moz-animation-delay: 18s;
    -moz-animation-duration: 5s;
    -moz-animation-name: fadeout;
    -moz-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -o-animation-delay: 18s;
    -o-animation-duration: 5s;
    -o-animation-name: fadeout;
    -o-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    animation-delay: 18s;
    animation-duration: 5s;
    animation-name: fadeout;
    animation-fill-mode: forwards; /* this prevents the animation from restarting! */
}

.c {
    background: url(../Images/experience-3.jpg) center center no-repeat pink;
    z-index: 5;

    -webkit-animation-delay: 33s;
    -webkit-animation-duration: 5s;
    -webkit-animation-name: fadeout;
    -webkit-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -moz-animation-delay: 33s;
    -moz-animation-duration: 5s;
    -moz-animation-name: fadeout;
    -moz-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -o-animation-delay: 33s;
    -o-animation-duration: 5s;
    -o-animation-name: fadeout;
    -o-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    animation-delay: 33s;
    animation-duration: 5s;
    animation-name: fadeout;
    animation-fill-mode: forwards; /* this prevents the animation from restarting! */
}

.d {
    background: url(../Images/experience-4.jpg) center center no-repeat green;
    z-index: 4;

    -webkit-animation-delay: 48s;
    -webkit-animation-duration: 5s;
    -webkit-animation-name: fadeout;
    -webkit-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -moz-animation-delay: 48s;
    -moz-animation-duration: 5s;
    -moz-animation-name: fadeout;
    -moz-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -o-animation-delay: 48s;
    -o-animation-duration: 5s;
    -o-animation-name: fadeout;
    -o-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    animation-delay: 48s;
    animation-duration: 5s;
    animation-name: fadeout;
    animation-fill-mode: forwards; /* this prevents the animation from restarting! */
}

.e {
    background: url(../Images/experience-5.jpg) center center no-repeat orange;
    z-index: 3;

    -webkit-animation-delay: 63s;
    -webkit-animation-duration: 5s;
    -webkit-animation-name: fadeout;
    -webkit-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -moz-animation-delay: 63s;
    -moz-animation-duration: 5s;
    -moz-animation-name: fadeout;
    -moz-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -o-animation-delay: 63s;
    -o-animation-duration: 5s;
    -o-animation-name: fadeout;
    -o-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    animation-delay: 63s;
    animation-duration: 5s;
    animation-name: fadeout;
    animation-fill-mode: forwards; /* this prevents the animation from restarting! */
}

.f {
    background: url(../Images/experience-6.jpg) center center no-repeat purple;
    z-index: 2;

    -webkit-animation-delay: 78s;
    -webkit-animation-duration: 5s;
    -webkit-animation-name: fadeout;
    -webkit-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -moz-animation-delay: 78s;
    -moz-animation-duration: 5s;
    -moz-animation-name: fadeout;
    -moz-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    -o-animation-delay: 78s;
    -o-animation-duration: 5s;
    -o-animation-name: fadeout;
    -o-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

    animation-delay: 78s;
    animation-duration: 5s;
    animation-name: fadeout;
    animation-fill-mode: forwards; /* this prevents the animation from restarting! */
}

...and what I want to do is to make it easier in future to change the values.

Just to explain that each class is applied to a div with a background image and each div is absolutely positioned on top of each other. So fading out the top div will show the other div below it.

The initial animation delay is 3 seconds and then the duration for each div is always 5 seconds.

But for each class I'm delaying the animation by the same amount of time it takes the previous animation to finish.

So the .b{} class is set to delay by 18 seconds. The way this is worked out is: the first animation has a 3 second delay + 5 second duration, which equals 8 seconds in total + 10 seconds extra for the user to properly see the next image.

So the c.{} class is set to delay by 33 seconds. And again the algorithm is: the second animation has a 18 second delay + 5 second duration, which equals 23 seconds in total + 10 seconds extra for the user to properly see the next image.

So this is the premise of the animation and I need to work out how to automate this via Sass (in case the client says "you know what, I want the duration to be 10 seconds now").

Thanks in advance for any help you can give me.

Upvotes: 2

Views: 2811

Answers (2)

Jordan Gray
Jordan Gray

Reputation: 16499

Step 1. Wrap it in a mixin, track duration with variables

For starters, you can wrap the whole block in a mixin and use some variables (global, so be careful) to track total duration and animation index:

$queue-max-z-index: 7;
$queue-total-delay: 0;
$queue-index: 0;

@mixin queue-animation($class, $color, $delay: 0, $duration: 5s, $viewing-time: 10s) {
    .#{$class} {
        background: url(../Images/experience-#{$queue-index + 1}.jpg) center center no-repeat $color;
        z-index: $queue-max-z-index - $queue-index;

        -webkit-animation-delay: $queue-total-delay + $delay;
        -webkit-animation-duration: $duration;
        -webkit-animation-name: fadeout;
        -webkit-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

        -moz-animation-delay: $queue-total-delay + $delay;
        -moz-animation-duration: $duration;
        -moz-animation-name: fadeout;
        -moz-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

        -o-animation-delay: $queue-total-delay + $delay;
        -o-animation-duration: $duration;
        -o-animation-name: fadeout;
        -o-animation-fill-mode: forwards; /* this prevents the animation from restarting! */

        animation-delay: $queue-total-delay + $delay;
        animation-duration: $duration;
        animation-name: fadeout;
        animation-fill-mode: forwards; /* this prevents the animation from restarting! */

        $queue-total-delay: $queue-total-delay + $delay + $duration + $viewing-time;
        $queue-index: $queue-index + 1;
    }
}

Now you can set up your animations like this:

@include queue-animation(a, red, 3s);
@include queue-animation(b, yellow);
@include queue-animation(c, pink);
@include queue-animation(d, green);
@include queue-animation(e, orange);
@include queue-animation(f, purple);

The function default values represent global defaults that you can override for an individual animation. Also note that it automatically tracks the count (index) of animations set up and the total duration of said animations, so you can alter the duration or delay on any one and all the subsequent animations will be updated.

Step 2. Clean up those prefixes

To refactor a little more, you could include a little helper I use for vendor prefixed properties:

// Apply common prefixes to a property.
@mixin prefix($property, $value, $apply-to: property, $prefixes: -webkit -khtml -moz -ms -o) {

    @if $apply-to == property {
        @each $prefix in $prefixes {
            #{$prefix}-#{$property}: $value;
        }

    } @else if $apply-to == value {
        @each $prefix in $prefixes {
            #{$property}: $prefix + -$value;
        }

    } @else if $apply-to == both {
        @each $prefix in $prefixes {
            #{$prefix}-#{$property}: $prefix + -$value;
        }
    }

    #{$property}: $value;
}

And now your function looks like this:

@mixin queue-animation($class, $color, $delay: 0s, $duration: 5s, $viewing-time: 10s) {
    .#{$class} {
        background: url(../Images/experience-#{$queue-index + 1}.jpg) center center no-repeat $color;
        z-index: $queue-max-z-index - $queue-index;

        @include prefix(animation-delay, $queue-total-delay + $delay);
        @include prefix(animation-duration, $duration);
        @include prefix(animation-name, fadeout);
        @include prefix(animation-fill-mode, forwards); /* this prevents the animation from restarting! */

        $queue-total-delay: $queue-total-delay + $delay + $duration + $viewing-time;
        $queue-index: $queue-index + 1;
    }
}

Step 3. Use the animation shorthand

Going a step further, you can use the animation shorthand:

@mixin queue-animation($class, $color, $delay: 0s, $duration: 5s, $viewing-time: 10s) {
    .#{$class} {
        background: url(../Images/experience-#{$queue-index + 1}.jpg) center center no-repeat $color;
        z-index: $queue-max-z-index - $queue-index;

        @include prefix(animation, fadeout $duration ($queue-total-delay + $delay) forwards);

        $queue-total-delay: $queue-total-delay + $delay + $duration + $viewing-time;
        $queue-index: $queue-index + 1;
    }
}

Humble disclaimer

I am still relatively new to Sass, so my advice is subjective and may not be in line with best practices. It's up to you how far you're happy to go with this, though, so feel free to ignore or modify any suggestions that make you feel uncomfortable.

Upvotes: 6

Miriam Suzanne
Miriam Suzanne

Reputation: 14010

Don't bother, there's a Compass plugin that will do it for you. That exact same code is being pulled into the Compass Core for the next release, so soon you wont even need to use a plugin. You get the added advantage that other people will help keep your animations code up-to-date. While you're at it, you can pull in the Compass port of Dan Eden's Animate.css.

Upvotes: 1

Related Questions