Animate SVG with JavaScript
Learn how to create crisp clean animated graphics with GreenSock's powerful GSAP Library.
There's so much that can be achieved natively in the browser using CSS3 or the Web Animations API, in JavaScript. Simple animations and transitions are well suited to CSS3 – whereas more complex animations need to be accomplished using JavaScript. (If you are creating a site without code, you need a website builder.)
The problem with the Web Animation API is browser support and the current feature set. Being a fairly young specification, this will improve in the coming years.
In order to combat this feature and browser support deficit, we can turn to animation libraries, such as GreenSock (GSAP). GSAP gives us the ability to create complex animations and multiple timelines, with the ability to animate almost any element or property/value pair – all achieved with a simple and intuitive syntax.
In this tutorial we're going to use the GSAP library to create a few animations. The main and most complex animation we will be creating will be transitioning the scene from day to night and we will see how easily we can chain together multiple transitions to create complicated animations. We'll also be creating a few simple animations that will be running constantly.
If you want more options for your animation project, check out our compilation of the best free graphic design software. Adding animation to a complex website? You'll need a supportive web hosting service.
Download the files for this tutorial.
01. Document setup
To start, we need to fork the GreenSock Pen in order to trial its premium plugins. For the tutorial we'll be using an SVG which has already been optimised and pasted into our HTML editor. However, if you're using your own SVG you'll need to make sure that all of the elements have unique IDs.
Get the Creative Bloq Newsletter
Daily design news, reviews, how-tos and more, as picked by the editors.
02. Create the first timeline
GSAP offers two timeline types: TimelineLite and TimelineMax. The TimeLineMax version offers access to additional features, such as the ability to repeat animations, as well as playing them in reverse among others. Our first timeline will be the water, which we will repeat infinitely and yoyo back and forth.
var animation_water = new TimelineMax({
repeat: -1,
yoyo: true
});
03. Create the first animation
In order to animate the water we have another path in our SVG, hidden with a '0' opacity. We'll utilise the morphSVG plugin to transform our original water path into the new water path. We'll move the water element '12px' down on the y-axis. The two numbers at the end of the property represent the delay and the start times respectively.
animation_water
.to("#water", 2, {
y: 12,
morphSVG:"#water-2",
ease:Linear.easeNone
}, 0 , 0)
;
04. Reusable properties
Since we will be reusing a number of properties and values a number of times we're going to create variables for these properties.
var animation_ease = Linear.easeNone;
05. Console logging
The GSAP library offers us the ability to get a number of properties from any given timeline. We can log these in the console to make sure that everything is working as we expect it to.
console.log(
'animation_water duration: '
+ animation_water.duration()
.toFixed(2)
);
06. Cloud timeline and console log
For every element we wish to animate separately and constantly, we need to create a new timeline. We also want to log that timeline in the console as we go.
var animation_cloud = new TimelineMax({
repeat: -1,
yoyo: true
});
console.log( '\n' +
...
animation_cloud.duration().toFixed(2) + ' \n'
);
07. Cloud animation
Now that we have our timeline ready, we can create our cloud animation. The section of animation which takes the new properties can handle multiple property/value pairs separated using commas.
Our cloud animation only needs to be subtle, so we only need to change the values by a small amount.
animation_cloud
.to("#cloud", 3, { x: -2, y: 1, scale: 0.95, rotation: 1, ease: animation_ease}, 0, 0)
;
08. Create the night time animation
Next, we'll start to create our day-to-night animation. We'll create a variable for the cycle time and the day. The 'yoyo' setting in GSAP also enables to us to delay the animation before repeating.
var day_night_cycle_time = 15;
var animation_delay = day_night_cycle_time / 2;
var animation_toNight = new TimelineMax({
repeat: -1,
yoyo: true,
repeatDelay: animation_delay
});
09. Animate the overlay layer
Inside our SVG we have an overlay layer made of a rectangle covering the entire image with the same background gradient as our night-time background. The overlay applies the 'multiply' blend mode in order to darken the entire image. Our animation simply transitions the opacity of this element.
animation_toNight
.to('#nighttime-overlay',
day_night_cycle_time, {
opacity: 1,
ease: animation_ease
}
, 0 , 0)
;
10. Animate the gradient
GSAP offers other tweens on top of the common 'to' and 'from' types. The tween type we need in order to animate our gradient is the 'staggerTo' tween. We can also use the 'cycle' property in order to rotate the colour wheel around to our new values.
.staggerTo('#daytime-gradient stop',
day_night_cycle_time, {
cycle:{
stopColor: ['#060414','#416584']
},
ease: animation_ease,
}, 0 , 0)
11. Animate the sun
We can keep adding animations to our 'toNight' animation. This time we'll add a new 'to' tween in order to set our sun. We'll set the display time to be a fraction of the cycle time in order to animate the sun before the moon. GSAP enables us to set almost any attribute. We'll use this in order to animate the 'cx' and 'cy' properties to below the hill on the right.
.to('#sun', day_night_cycle_time / 1.25, {
scale: 0.9,
attr:{cx:"753", cy:"697"},
ease:animation_ease}
, 0, 0)
12. Animate the moon
We'll use the same technique we used to animate the sun out of view (see Step 11 above) in order to animate the moon into view. We could achieve this using one tween, of course, but in order to create a faux arc we'll do this is in two parts. In both parts we're also going to apply a new value to the scale property.
.to('#moon', day_night_cycle_time / 2, {
scale: 0.9,
attr:{cx:"174.5", cy:"202.5"},
ease:animation_ease}
, 0 , 0)
The second part of the moon animation waits for the first section to finish before it begins. Note: these two parts of the moon animation are chained together inside the animation code along with the other day-to-night properties that we're using.
animation_toNight
...
.to('#moon', day_night_cycle_time / 2, {
scale: 0.9,
attr:{cx:"410.5", cy:"114.5"},
ease:animation_ease}
, day_night_cycle_time / 2, 0)
;
13. Animate the stars
The only part left of our day-to-night animation are the stars. We'll animate the stars into view by transitioning a number of properties. The first of them is to simply bring them into view by animating their opacity.
.to('#stars', day_night_cycle_time/2,
{opacity: 1},
day_night_cycle_time/2,
0)
Next we'll use the 'from' tween in order to move the stars up and rotate them from a negative angle as they animate into view. We're using some simple maths in order to calculate our animation time and delay, all based on our 'day_night_cycle_time' variable.
.from("#stars",
day_night_cycle_time - (day_night_cycle_time / 4),
{y: 150, rotation: -15, ease: animation_ease},
day_night_cycle_time / 4,
0)
14. Create the stars timeline and the console log
Now we've created our day-to-night animation, we can create another constant animation to make our stars blink. We'll create the new timeline and then log the timeline duration in the console.
var animation_stars = new TimelineMax({
repeat: -1,
yoyo: true
});
15. Make the stars blink
Now we've created the timeline ready for animation, we need to create our blinking animation. The animation is really simple – all we want to do is reduce the opacity value. Thanks to the 'yoyo' property, the opacity will animate on and off and so will make the stars look like they are blinking.
animation_stars
.to("#stars", 0.5,
{opacity: 0.5, ease: animation_ease}
, 0, 0)
;
16. Delay the blinking
In the last step we're targeting the stars group in order to apply our blinking animation, however it would look much better if the stars were to blink one at a time instead of together at the same time. We achieve this by targeting each star separately and applying a different animation.
animation_stars
…
.to("#star-two", 0.5,
{opacity: 0.5, ease: animation_ease}
, 1.25, 0)
.to("#star-three", 0.5,
{opacity: 0.5, ease: animation_ease}
, .75, 0)
… ;
17. Add snow
That's it! Our day-to-night cycling animation is finished and it looks awesome, but we don't have to stop there. Since the image is in SVG we can easily add new elements to our landscape. Let's add some snow. We'll do this using two separate layers. Each layer has a collection of ellipses large enough to cover the landscape and then the same collection repeated above.
<g id="snow-bottom-layer" …>
...
<ellipse …/>
</g>
<g id="snow-top-layer" …>
...
<ellipse …/>
</g>
18. Create the snow timelines
We create two separate timelines for our snow in order to be able to animate them over different durations. We'll also log their durations to the console.
var animation_snowTop = new TimelineMax({
repeat: -1,
repeatDelay: 0
});
var animation_snowBottom = new TimelineMax({
repeat: -1,
repeatDelay: 0
});
19. Animate the snow
In order to animate our snow layers we want to move the two layers along the vertical axis. By differing their durations we will get the appearance of the layers moving at different speeds. The animation works by moving the collection of ellipses along the vertical axis until the second collection is in place of the first. We then repeat the animation.
animation_snow
.to("#snow-top-layer", 7,
{attr: {transform: "translate(24 -108)"}
, ease: animation_ease}
, 0, 0)
;
Find the full collection of tutorial Pens here. Need somewhere secure to store your files? See our guide to cloud storage.
This article was originally published in creative web design magazine Web Designer. Subscribe to Web Designer here.
Related articles:
Thank you for reading 5 articles this month* Join now for unlimited access
Enjoy your first month for just £1 / $1 / €1
*Read 5 free articles per month without a subscription
Join now for unlimited access
Try first month for just £1 / $1 / €1
Steven is a digital creative from Stockton-on-Tees, UK. An experienced Head of UX, Steven has written a number of articles on web design and front-end development, as well as delivering a talk at CSSConf Budapest on the potential of CSS animations. He is currently Head of UX at Aero Commerce.