SVG Animation Three Ways: CSS Animation
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:
animation-delay
animation-direction
animation-duration
animation-iteration-count
animation-name
animation-play-state
animation-timing-function
animation-fill-mode
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
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: