« Back to Blog

SVG Animation Three Ways, Part 3: CSS Animation

By Claire Remmert
May 21, 2018

Part 3: Making the leaf dance with CSS Animation

(In my best ABBA voice) You are the dancing leeeeaaaf! Feel the beat, you are small and greeeen.. OOOOooooooo

Welcome to the final installment of my series on animating SVG! By now, we’ve got a veritable party jungle of party leaves to enhance the party for our party parrot friends. Thus far we’ve learned to animate using JavaScript, using SMIL (although this will probably soon be deprecated) and now we will learn the exceedingly powerful greatness of CSS Animation!

Check out the first two installments: Part 1: JavaScript Disco Leaf Part 2: SMIL Scrolling Gradient

CSS animations can be used to animate the transition from one style to another, and anything you can imagine in between (well, within the animate-able properties of course). Animations consist of both the properties describing the animation itself, and a set of keyframes that set start, intermediate and end states of the animation. Essentially, animation (and sub-properties) is how to animate, and the @keyframes is when to transition to what.

Using CSS Animation

First, let’s break down the animation property and sub-properties. The various ways to configure an animation are thusly:

If you wish, you can combine the various properties of your animation into one line using simply animation. You can learn more about using these properties from this helpful MDN overview.

What are CSS keyframes?

CSS Keyframes refers to the @keyframes at rule that lets you define the actual styles and sequence of steps for those styles.

The @keyframes set is given a name that you call when you set the animation property, or using animation-name’. In this example, the set is called bumpit`.

@keyframes bumpit {
    0% {
        transform: scale(.95);
    }
    50% {
        transform: scale(1);
		  }
    100% {
        transform: scale(.95);
}
.dancing-leaf .leaf {
	animation: bumpit 1s ease infinite;  
}		

Animating the Dancing Leaf

To start, I need to get my SVG code. A reminder: SVG stands for Scalable Vector Graphics, an XML-based markup language to build two-dimensional vector graphics.

<svg class="dancing-leaf" width="100%" height="auto" viewBox="0 0 53 87" version="1.1">
	    <defs>
	        <polygon id="path-1" points="52.67871 0.617407954 0 0.617407954 0 86.5269756 52.67871 86.5269756"></polygon>
	    </defs>
	    <g class="leaf" id="Page-1" stroke="none" stroke-width="1" fill="none">
	       <g id="Fill-1-Clipped">
	           <mask id="mask-2" fill="white">
	               <use xlink:href="#path-1"></use>
	           </mask>
	           <g id="path-1"></g>
	           <path class="leaf-fill" d="M47.76201,37.2875647 L28.79811,46.8794704 L28.79811,28.2616913 L47.82321,18.6869108 C47.84481,18.8698798 47.76201,19.0555529 47.76201,19.2430286 L47.76201,37.2875647 Z M26.22231,24.0984688 L7.62291,14.7850728 L26.13591,5.48068984 L44.80461,14.7931847 L26.22231,24.0984688 Z M23.88141,46.8794704 L4.56561,37.2875648 L4.56561,19.227706 C4.56561,19.044737 4.65831,18.8644719 4.67811,18.6860094 L23.88141,28.2616913 L23.88141,46.8794704 Z M23.88141,70.860136 L7.29261,62.5931788 C5.66001,61.7756767 4.56561,60.1316588 4.56561,58.3037707 L4.56561,42.6495499 L23.88141,52.2414556 L23.88141,70.860136 Z M47.31201,10.5578563 L47.28321,10.5578563 L28.16361,1.07681355 C26.89821,0.444984388 25.38171,0.47292548 24.11811,1.10745862 L5.22621,10.6425809 C1.96911,12.2802892 -9e-05,15.5773379 -9e-05,19.227706 L-9e-05,58.3037707 C-9e-05,61.9604482 1.99701,65.2475824 5.26221,66.8825867 L23.88141,76.2221214 L23.88141,86.5269756 L28.79811,86.5269756 L28.79811,76.2221214 L28.79811,70.860136 L28.79811,52.2468637 L28.79811,52.2414556 L47.76201,42.6495499 L47.76201,58.3037707 C47.76201,60.1316588 46.73151,61.7756767 45.09891,62.5931788 L33.36291,68.461709 L33.36291,73.8236943 L47.30391,66.8825867 C50.57001,65.2475824 52.67871,61.9604482 52.67871,58.3037707 L52.67871,19.2430286 C52.67871,15.5800418 50.58621,12.3163423 47.31201,10.5578563 Z" id="Fill-1" fill="#58BA57" fill-rule="nonzero"></path>
            </g>
        </g>
    </g>
</svg>

In order to animate elements within the leaf, I use the css classes dancing-leaf on the <svg> element itself, leaf on the <g> shape, and leaf-fill to target the <path> that represents the fill.

Then I create the keyframes to define the animation effect that I want. I’m imagining a strobe-light, pulsing neon leaf worthy of a party parrot jungle party. For simplicity and flexibility, I separated the size transform and the color changing into two @keyframes.

@keyframes bumpit {
    0%   { transform: scale(.95); }
    50%  { transform: scale(1); }
    100% { transform: scale(.95); }
}
@keyframes flash {
    0%    { fill: #EF696A; /*orange*/ }
	12.5% { fill: #87FFFE; /*blue*/ }
	25%   { fill: #F36ABA; /*pink*/ }
	37.5% { fill: #F8F58A; /*yellow*/ }
	50%   { fill: #88FF89; /*green*/ }
	62.5% { fill: #EF696A; /*orange*/ }
	75%   { fill: #88FF89; /*green*/ }
	87.5% { fill: #F8F58A; /*yellow*/ }
	100%  { fill: #F36ABA; /*pink*/ }
}

I wanted enough keyframes in flash to cycle through all the colors at least once and have the correct number of frames for my timing to work out.

Then, to define the properties of how I want these keyframes to animate, I set the animate property on my class selectors.

.dancing-leaf .leaf {
    transform-origin: 50% 50%;
	animation: bumpit 1s ease infinite;  
}
.dancing-leaf .leaf .leaf-fill {
	animation: flash 4s ease infinite;
}

The bumpit animation has three frames, including at 0% and 100%, which can be counted as one. So over the course of one second, a pulse happens every .5 seconds. My flash set has eight frames, if we count the 0% and 100% as one. I wanted the fill to change at each beat of the bumpit pulse, so by running at a loop speed of 4 seconds, a change will also happen every .5 seconds. I set an animation-timing-function of ease, and an animation-iteration-count of infinite so the party never has to end.

I also set transform-origin of the shape, so the pulse will happen outward from the center rather than the default 0,0 origin.

The Final Product

View in JSFiddle

Browser support

In terms of support, CSS animations are a good option. Pretty much all modern browsers have supported them for a few years, enough to be confident that your animation will behave as expected, but it’s always a good idea to pay attention to how your site functions without this capability if you’re going to use it.

When to use CSS Animation versus JS or SMIL

SMIL animations are most likely going to be deprecated soon, and so don’t make much sense to use unless there’s a particular need that only SMIL can fulfill. CSS animations are often the most simple and straightforward way to implement an animation, without having to load or learn any JavaScript if that’s not your bag.

If you’re interested in web animation in general, I would suggest looking into the Web Animations API, which allows you to harness the full browser animation model through JavaScript. This API is still building support across browsers, but it’s definitely worth the time to look into and understand.

For a good intro and comparison between CSS Animation and the Web Animations API, check out these articles: