The animation-direction CSS property controls how an animation will play. There are four possible settings:
normal (default) - the animation plays forwards (from-to, or 0% to 100%)
reverse - the animation plays backwards (to-from, or 100% to 0%)
alternate - the animation plays forwards, then backwards
alternate-reverse - the animation plays backwards, then forwards
This is the animation we'll be applying different fill-modes to. It's a simple scaling of a rect element.
1
2
3
4
5
6
7
8
9
10
<style>
@keyframes grow {
from {
transform: scale(1);
}
to {
transform: scale(2.5);
}
}
</style>
1
2
3
4
5
6
7
8
9
10
<style>
@keyframes grow {...}
#normalAnimation {
// animation duration, timing etc.
animation-direction: normal;
}
</style>
<rect id="normalAnimation"... />
animation-direction: normal;
animation-direction: reverse;
animation-direction: alternate;
animation-direction: alternate-reverse;
The animation-fill-mode property defines how styles are applied to the styled object before and/or after the animation occurs. There are four possible values:
animation-fill-mode: none | forwards | backwards | both
The examples below are all identical other than their fill-mode setting - after a delay of 1 second the square scales from 2x to 4x and turns from red to blue. See if you can notice how the fill-mode affects the animation!
The animation styles are only applied during the animation. So the square stays grey and it's normal size during the delay. When the delay is over, the styles defined in the first keyframe are applied (red fill, 2x scale). When the animation is over, all styles from the animation are removed and the square returns to it's pre-animation state.
animation-fill-mode: none
When the animation competes, the object retains the styles as defined in the final keyframe of the animation. So the square stays blue and scaled to 4x.
animation-fill-mode: forwards
Before the animation runs, the object takes on the styles as defined in the first keyframe. So the square immediately takes on the styles as set forth at the start of the animation - red and a scale of 2x. After the animation is complete, all styles from the animation are removed.
animation-fill-mode: backwards
The object takes on the styles as defined in the first keyframe prior to the animation running (red, 2x scale), and retains the styles as defined in the final keyframe after running (blue, 4x scale).
animation-fill-mode: both
Due to the way browsers have implemented CSS transforms with SVGs, it can be difficult at times to predict what the user will see when animating the transform property.
For example, here's a video of a simple animation that moves circle from one side of the svg to another.
1
2
3
4
5
6
7
8
@keyframes slide {
from {
transform: translateX(0px);
}
to {
transform: translateX(400px);
}
}
When we change the zoom settings on our browser, the animation looks just fine - at least with current mac versions of Chrome and Firefox.
But look what happens to the animation when we change the browsers zoom settings in Safari - the animation doesn’t go all the way to the edge anymore! The example below has the zoom settings set to 200%
So Chrome and FireFox both require the use of units for CSS translations - px or % - which they then ignore in favor of the SVG’s coordinate system. Safari, on the other hand, takes the unit designation seriously, and will translate the circle the distance specified - at least at the time of this writing.
Here's another example. This time we'll create a simple animation to spin a square.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style>
#spinner {
animation-name: spin;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration: infinite;
transform-box: fill-box;
transform-origin: center;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>
To rotate the cube around its center point, we can add set transform-box to fill-box and transform-origin to "center".
While everything looks fine in Chrome and Firefox, things start to get weird in Safari when you change the zoom settings. The video below is of the same animation running in Safari with the zoom settings at 200%
In conclusion: CSS animations are great for SVGs unless you need to animate a transform property. Due to the inconsistent and downright buggy browser implementation for CSS transforms with SVGs, it’s best to use JavaScript to dynamically update the transform presentation attributes over time, as we’ll see in the following section.