SVG Animation (with tutorial examples)
Step by Step Guide on Getting Started with SVG Animation
Photo by Pankaj Patel on Unsplash
What is an SVG? ๐ค
SVGs are scalable vector graphics. They are XML-based vector image formats, much like how HTML(Hyper Text Markup Language) works. It defines different elements for familiar geometric shapes that can be combined in XML(eXtensible Markup Language) text files to produce two-dimensional(2d) graphics.
Since Scalable Vector Graphics(SVG) are XML Documents, it looks more like HTML at first glance. You can add CSS(Cascading Style Sheet) classes and ids so you can manipulate them just like HTML elements.
Getting the SVG from Undraw:
Undraw is a platform where you can get free and open-sourced illustrations in .svg or .png format.
When you select an image on unDraw, you are able to change its colour and also select the download format.
I would be using the aircraft image for this tutorial.
Simply type aircraft in the search box.
Optimising the SVG code:
After downloading the SVG image. Open it up in any code editor of your choice.
I would be using VScode for this tutorial.
I put every code-related folder and file in the Documents folder on my PC
$cd Documents
$mkdir svg-animation
Go ahead and open the folder in your VScode and add the downloaded SVG image to the folder.
After doing that, you would be faced with an incomprehensible wall of text ๐ฌ, but not to worry, together we would figure out how to optimise and make it less scary. ๐
SVG Elements:
MDN is one website that has an incredible resource for developers and the documentation on SVGs is superb. I urge you to go read more and dig deeper on your own.
As we look at our SVG file, we will notice that is it made of the following elements:
<svg>
,<path>
,<polygon>
,<ellipse>
,<circle>
,<rect>
,<g>
, .
Let's try to make things a little more readable, that would make it easier for us to manipulate these elements. ๐
Optimization:
Let's start with the <path>
element.
In VScode, select the <path>
element and shift + ctrl + L
on your keyboard will select the <path>
tag everywhere on the file, backspace <
to the beginning of the element and hit enter
You should have something like this
Now do this for every element listed above.
Animation:
This is the part I am most excited about because I love animations, the thought of making something still come to life always excites me.
I would be talking about two ways in which we can add CSS styling to our SVG.
We can add CSS styles in a <style>
tag, embedded inside the <svg>
tag:
<svg xmlns="http://www.w3.org/2000/svg" width="993.73022" height="422.32217" viewBox="0 0 993.73022 422.32217" xmlns:xlink="http://www.w3.org/1999/xlink">
<style>
</style>
We would start with the SVG Element itself (container element).
Let's change the size of the SVG image, we can do that by changing the width of the image to 600
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="422.32217" viewBox="0 0 993.73022 422.32217" xmlns:xlink="http://www.w3.org/1999/xlink">
<style>
</style>
Another thing we would change is the fill colour
of the first <path>
element. Add a CSS class of .red to it and give it a fill colour of red.
<svg xmlns="http://www.w3.org/2000/svg" width="993.73022" height="422.32217" viewBox="0 0 993.73022 422.32217" xmlns:xlink="http://www.w3.org/1999/xlink">
<style>
.red{
fill: red;
}
</style>
<path class="red" d="M608.03796,422.32217h-221.40814c-6.26141,0-11.35526-5.0943-11.35526-11.35526V11.35525c0-6.26094,5.09384-11.35525,11.35526-11.35525h221.40814c6.26141,0,11.35522,5.09431,11.35522,11.35525V410.96692c0,6.26093-5.09381,11.35526-11.35522,11.35526ZM473.16803,1.89625c-53.01779,0-95.99719,42.97942-95.99719,95.99722V410.96692c0,5.22406,4.23495,9.45901,9.45901,9.45901h221.40811c5.22406,0,9.45898-4.23492,9.45898-9.45898V11.35525c0-5.22407-4.23492-9.45901-9.45898-9.45901h-134.86993Z" fill="#e6e6e6"/>
Open it up in your browser and you should have something like this.
So let's start out by identifying the SVG elements and figuring out which is which.
You can choose to use the method of adding a class to the element, then change the fill colour or change the fill colour directly
Let's try that with the second path element.
I changed the fill colour to red, then I was able to note what position it is in the Image.
<!-- line at the top of plane -->
<path d="M618.24402,105.3093c0,.67684,.75897,1.2203,1.70404,1.2203h292.52301c.94501,0,1.70398-.54346,1.70398-1.2203,0-.67678-.75897-1.2203-1.70398-1.2203h-292.52307c-.94513,0-1.70404,.54352-1.70404,1.2203h.00006Z" fill="#ff0000"/>
Using this method I have gone ahead and renamed every element accordingly
<!-- left leg of plane -->
<polygon points="380.33884 279.58173 383.23392 356.30087 376.18716 356.30087 376.18716 364.98608 395.88272 364.98608 395.88272 356.30087 390.13818 356.30087 390.54849 279.58173 380.33884 279.58173" fill="#3f3d56"/>
<!-- left tire of the left leg of plane -->
<path d="M372.73932,343.99686h-.00003c2.99792,0,5.42825,2.43033,5.42825,5.42825v22.43671c0,2.99792-2.43033,5.42825-5.42825,5.42825h.00003c-2.99792,0-5.42825-2.43033-5.42825-5.42825v-22.43671c0-2.99792,2.43033-5.42825,5.42825-5.42825Z" fill="#3f3d56"/>
<!-- right tire of the left leg of plane -->
<path d="M400.2424,343.99686h-.00003c2.99792,0,5.42825,2.43033,5.42825,5.42825v22.43671c0,2.99792-2.43033,5.42825-5.42825,5.42825h.00003c-2.99792,0-5.42825-2.43033-5.42825-5.42825v-22.43671c0-2.99792,2.43033-5.42825,5.42825-5.42825Z" fill="#3f3d56"/>
Animation Example
This is the full animation example. This would be the final result of the animated image when we are done. Let's get right on it ๐ฏ
Step By Step
There are not a lot of complex things going on. The difficult part was going through each of the <svg>
elements and labelling each part accordingly.
After that, I added a fly animation to the main <svg>
element.
svg{
transform-box:fill-box;
transform-origin:center;
animation:fly 4s infinite ease-in-out;
}
@keyframes fly{
0%{
transform:scale(0.1);
}
5%{
transform:scale(0.2);
}
10%{
transform: rotate(-20deg);
transform:scale(0.2);
}
15%{
transform:scale(0.4);
}
20%{
transform:scale(0.5);
}
25%{
transform:scale(0.6);
}
30%{
transform:scale(0.6);
}
40%{
transform: rotate(-20deg);
}
80%{
transform: rotate(20deg);
}
100%{
transform:rotate(-20deg);
}
}
After a lot of searching ๐ช, I found the code for the little round purple balls at the top and bottom of the plane.
Isn't it funny that these cute balls were sitting at the bottom of the code all this while I was searching for them, ๐?
Also, I animated the balls, so they bend towards the angle the plane is bending towards.
.ball{
animation: ball 3s linear alternate infinite;
}
@keyframes ball {
0% {
transform: translate(150px);
}
50%{
transform: translate(-20px);
}
100%{
transform: translate(150px);
}
}
Complete Code
There are other ways you can add animations to your <svg>
but I have decided to focus on having everything in one file for this tutorial.
There are a lot of use cases for this kinda approach for example you can share this <svg>
with a friend or colleague without any other file. They will open it up in their code editor and see what you have done. No additional file is needed, isn't that cool? ๐
Also, you can add this image to your README.md
file and you would have cute animations that give life to your readme
file.
Is that the kinda thing you may be interested in? Then you should read this article by Eamonn Cottrell. He spoke in long length on how you can ~ Add Animations to SVGs for GitHub READMEs.
Here is the full code file with everything within the .svg:
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="422.32217" viewBox="0 0 993.73022 422.32217" xmlns:xlink="http://www.w3.org/1999/xlink">
<style>
svg{
transform-box:fill-box;
transform-origin:center;
animation:fly 4s infinite ease-in-out;
}
.rotate{
transform-box:fill-box;
transform-origin:center;
animation:rotate 2s infinite linear;
}
@keyframes rotate{
0%{transform:rotate(0deg)}
100%{transform:rotate(359deg)}
}
.ball{
animation: ball 3s linear alternate infinite;
}
@keyframes ball {
0% {
transform: translate(150px);
}
50%{
transform: translate(-20px);
}
100%{
transform: translate(150px);
}
}
@keyframes fly{
0%{
transform:scale(0.1);
}
5%{
transform:scale(0.2);
}
10%{
transform: rotate(-20deg);
transform:scale(0.2);
}
15%{
transform:scale(0.4);
}
20%{
transform:scale(0.5);
}
25%{
transform:scale(0.6);
}
30%{
transform:scale(0.6);
}
40%{
transform: rotate(-20deg);
}
80%{
transform: rotate(20deg);
}
100%{
transform:rotate(-20deg);
}
}
</style>
<!-- rectangle box covering plane -->
<path d="M608.03796,422.32217h-221.40814c-6.26141,0-11.35526-5.0943-11.35526-11.35526V11.35525c0-6.26094,5.09384-11.35525,11.35526-11.35525h221.40814c6.26141,0,11.35522,5.09431,11.35522,11.35525V410.96692c0,6.26093-5.09381,11.35526-11.35522,11.35526ZM473.16803,1.89625c-53.01779,0-95.99719,42.97942-95.99719,95.99722V410.96692c0,5.22406,4.23495,9.45901,9.45901,9.45901h221.40811c5.22406,0,9.45898-4.23492,9.45898-9.45898V11.35525c0-5.22407-4.23492-9.45901-9.45898-9.45901h-134.86993Z" fill="#e6e6e6"/>
<!-- line at the top of plane -->
<path d="M618.24402,105.3093c0,.67684,.75897,1.2203,1.70404,1.2203h292.52301c.94501,0,1.70398-.54346,1.70398-1.2203,0-.67678-.75897-1.2203-1.70398-1.2203h-292.52307c-.94513,0-1.70404,.54352-1.70404,1.2203h.00006Z" fill="#e6e6e6"/>
<!-- left leg of plane -->
<polygon points="380.33884 279.58173 383.23392 356.30087 376.18716 356.30087 376.18716 364.98608 395.88272 364.98608 395.88272 356.30087 390.13818 356.30087 390.54849 279.58173 380.33884 279.58173" fill="#3f3d56"/>
<!-- left tire of the left leg of plane -->
<path d="M372.73932,343.99686h-.00003c2.99792,0,5.42825,2.43033,5.42825,5.42825v22.43671c0,2.99792-2.43033,5.42825-5.42825,5.42825h.00003c-2.99792,0-5.42825-2.43033-5.42825-5.42825v-22.43671c0-2.99792,2.43033-5.42825,5.42825-5.42825Z" fill="#3f3d56"/>
<!-- right tire of the left leg of plane -->
<path d="M400.2424,343.99686h-.00003c2.99792,0,5.42825,2.43033,5.42825,5.42825v22.43671c0,2.99792-2.43033,5.42825-5.42825,5.42825h.00003c-2.99792,0-5.42825-2.43033-5.42825-5.42825v-22.43671c0-2.99792,2.43033-5.42825,5.42825-5.42825Z" fill="#3f3d56"/>
<!-- left small wing of plane -->
<polygon points="444.39209 231.78143 332.93219 226.71507 350.30258 218.75365 448.01093 220.20119 444.39209 231.78143" fill="#B763FF"/>
<polygon points="0 243.03156 13.4609 237.96519 431.36432 248.82169 448.73471 240.86026 441.49704 290.07632 109.53795 254.70364 0 243.03156" fill="#B763FF"/>
<polygon points="107.4792 271.6203 109.53795 254.70364 441.49704 290.07632 439.68762 315.04623 107.4792 271.6203" fill="#3f3d56"/>
<!-- left light of plane -->
<ellipse class="rotate" cx="330.76089" cy="285.00998" rx="34.37888" ry="36.55017" fill="#3f3d56"/>
<circle cx="330.76089" cy="278.49609" r="25.33179" fill="#B763FF"/>
<!-- RIGHT SIDE OF PLANE
-->
<!-- right leg of plane -->
<polygon points="613.39136 279.58173 610.49634 356.30087 617.54303 356.30087 617.54303 364.98608 597.84753 364.98608 597.84753 356.30087 603.59204 356.30087 603.1817 279.58173 613.39136 279.58173" fill="#3f3d56"/>
<!-- right tire of the right leg of plane -->
<rect x="615.56262" y="343.99686" width="10.85651" height="33.29321" rx="5.42822" ry="5.42822" fill="#3f3d56"/>
<!-- left tire of the right leg of plane -->
<rect x="588.05963" y="343.99686" width="10.85651" height="33.29321" rx="5.42822" ry="5.42822" fill="#3f3d56"/>
<polygon points="549.33813 231.78143 660.79803 226.71507 643.42767 218.75365 545.7193 220.20119 549.33813 231.78143" fill="#B763FF"/>
<polygon points="509.44403 216.18808 504.37772 104.72817 496.41629 122.09854 497.8638 219.8069 509.44403 216.18808" fill="#B763FF"/>
<polygon points="993.73022 243.03156 980.26935 237.96519 562.36591 248.82169 544.99554 240.86026 552.23315 290.07632 884.19226 254.70364 993.73022 243.03156" fill="#B763FF"/>
<polygon points="886.25104 271.6203 884.19226 254.70364 552.23315 290.07632 554.0426 315.04623 886.25104 271.6203" fill="#3f3d56"/>
<!-- right light of plane -->
<ellipse cx="662.96936" cy="285.00998" rx="34.37885" ry="36.55017" fill="#3f3d56"/>
<circle cx="662.96936" cy="278.49609" r="25.33179" fill="#B763FF"/>
<path d="M560.01367,217.89745l-1.64294,12.10632-.854,65.16789c-.06519,4.84918-.65143,9.64053-1.75153,14.28714-3.1701,13.53439-10.57422,25.84564-21.51038,34.76971-9.92279,8.10614-23.45718,14.24365-41.37039,13.15802-47.76852-2.89505-51.9881-43.54901-51.9881-43.54901l1.80219-73.72276,.24609-10.11098,2.1713-18.24385s5.79013-51.38736,59.34879-49.93983c53.55869,1.44753,55.54898,56.07735,55.54898,56.07735Z" fill="#B763FF"/>
<polygon points="456.69611 200.90344 467.55261 183.53307 481.30414 179.19048 528.34894 179.19048 539.9292 183.53307 550.43805 200.90344 531.24396 192.21826 477.40039 192.21826 456.69611 200.90344" fill="#e6e6e6"/>
<g>
<!-- front left of plane -->
<polygon points="496.50888 325.78528 498.36609 375.00134 493.84552 375.00134 493.84552 380.57297 506.48041 380.57297 506.48041 375.00134 502.79523 375.00134 503.05847 325.78528 496.50888 325.78528" fill="#3f3d56"/>
<!-- left tire of plane -->
<path d="M491.6337,367.10818h0c1.92322,0,3.48227,1.55905,3.48227,3.48227v14.39337c0,1.92322-1.55905,3.48227-3.48227,3.48227h0c-1.92322,0-3.48227-1.55905-3.48227-3.48227v-14.39337c0-1.92322,1.55905-3.48227,3.48227-3.48227Z" fill="#3f3d56"/>
<!-- right tire of plane -->
<path d="M509.27719,367.10818h0c1.92322,0,3.48227,1.55905,3.48227,3.48227v14.39337c0,1.92322-1.55905,3.48227-3.48227,3.48227h0c-1.92322,0-3.48227-1.55905-3.48227-3.48227v-14.39337c0-1.92322,1.55905-3.48227,3.48227-3.48227Z" fill="#3f3d56"/></g>
<rect x="460.31845" y="185.7903" width="37.36307" height="1.99969" transform="translate(170.83368 598.33002) rotate(-74.47739)" fill="#B763FF"/>
<rect x="529.99975" y="174.10844" width="2.00043" height="37.3632" transform="translate(-27.20847 106.00117) rotate(-11.11698)" fill="#B763FF"/>
<!-- top ball on line -->
<circle class="ball" cx="734.41626" cy="103.75365" r="13" fill="#B763FF"/>
<!-- ball on rectangle -->
<circle cx="374.6018" cy="146.30627" r="13" fill="#B763FF"/>
<!-- a bottom line of plane -->
<path d="M80.244,390.3093c0,.67685,.75895,1.22031,1.70405,1.22031H374.4711c.94501,0,1.70398-.54346,1.70398-1.22031,0-.67679-.75894-1.22031-1.70398-1.22031H81.94805c-.9451,0-1.70405,.54352-1.70405,1.22031Z" fill="#e6e6e6"/>
<!-- bottom ball on line -->
<circle class="ball" cx="196.41629" cy="388.75366" r="13" fill="#B763FF"/></svg>
Appreciation
I want to sincerely appreciate She Code Africa. This is my 3rd month as a mentee on the SCA Mentoring Program cohort 6. It has been a huge, huge impact on my career and growth. Massive thanks to the sponsors ๐, you played a big part in the success of this program.
I hope you enjoyed reading as much as I enjoyed writing ๐คฉ.
Want to say hello ๐ ? You can reach out to me on Twitter - Vickish11, let me know how much this article has helped you get started with SVG Animations.
Thanks for reading ๐๐