Simple SVG animation with CSS

                 
👉🏼 Here you find the full repository
https://github.com/DenisCangemi/Phone-icon-ringing-animation ✌️🏻

In this article I will show you how to animate an svg image, in particular we’ll animate a simple ringing phone icon 📱 as below

It’s a good start if you’re new with web development, we’ll see HTML and CSS codes, animation in CSS and you’ll learn how to work with SVG images.

The elements we’ll animate are two: the phone and the sounds waves symbols on the sides and we’ll see all the steps to create it:

◾ Create the project folder

◾ Taking the image

◾ Optimize svg with SVGO

◾ Phone ringing animation

◾ Sounds waves animation

Create the project folder

Let’s start creating the project folder which will contain our project files.

We’ll work in a Windows environment but we’ll use very simple commands you can translate in your OS.

Open the CMD and position yourself in your projects folder and type

mkdir ringingPhoneAnim

Enter the folder

cd ringingPhoneAnim

Then create all the nedded files: we’ll use one HTML file and one separeted CSS file, plus we’ll create an images folder for the svgs

Echo > “index.html”
Echo > “index.css”
mkdir images

Now copy and paste the image downloaded before, smartphone.svg, inside the images folder

You should have this

|-- ringingPhoneAnim
|-- index.html
|-- index.css
|-- images
|-- smartphone.svg

Taking the image

For the tutorial, we’ll use a phone flat style icon from Flaticon, you can find the image source here.

If you will use this image for a real application, insert this snippet to credit the image author
<div>Icons made by <a href=”https://www.flaticon.com/authors/smashicons" title=”Smashicons”>Smashicons</a> from <a href=”https://www.flaticon.com/" title=”Flaticon”>www.flaticon.com</a> is licensed by <a href=”http://creativecommons.org/licenses/by/3.0/" title=”Creative Commons BY 3.0" target=”_blank”>CC 3.0 BY</a></div>

Optimize the image with SVGO

If you open smartphone.svg with a file editor, you will see the image xml tags and you can easily identify which are the tags which compose the image, like <path /> and <circle />.
These are two of the basics tags in the svg sintax and in simple term, <path /> with ‘d’ property let you draw free lines and elements like circle or rect, let you draw basic geometric shapes and they have differents properties each other like this

<circle style=”fill:#FFFFFF;” cx=”29.999" cy=”53.999" r=”3"/>
<?xml version=”1.0" encoding=”iso-8859–1"?>
<! — Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) →
<svg version=”1.1" id=”Capa_1" xmlns=”http://www.w3.org/2000/svg" xmlns:xlink=”http://www.w3.org/1999/xlink" x=”0px” y=”0px”
viewBox=”0 0 59.998 59.998" style=”enable-background:new 0 0 59.998 59.998;” xml:space=”preserve”>
<path style=”fill:#E7ECED;” d=”M42.594,58.999H17.404c-1.881,0–3.405–1.525–3.405–3.405V4.404c0–1.881,1.525–3.405,3.405–3.405
h25.189c1.881,0,3.405,1.525,3.405,3.405v51.189C45.999,57.474,44.474,58.999,42.594,58.999z”/>
<circle style=”fill:#FFFFFF;” cx=”29.999" cy=”53.999" r=”3"/>
<path style=”fill:#424A60;” d=”M29.999,4.999h-4c-0.553,0–1–0.447–1–1s0.447–1,1–1h4c0.553,0,1,0.447,1,1S30.552,4.999,29.999,4.999
z”/>
<path style=”fill:#424A60;” d=”M33.999,4.999h-1c-0.553,0–1–0.447–1–1s0.447–1,1–1h1c0.553,0,1,0.447,1,1S34.552,4.999,33.999,4.999
z”/>
<path style=”fill:#7383BF;” d=”M55.904,21.241c-0.256,0–0.512–0.098–0.707–0.293c-0.391–0.391–0.391–1.023,0–1.414
c3.736–3.736,3.736–9.815,0–13.552c-0.391–0.391–0.391–1.023,0–1.414s1.023–0.391,1.414,0c4.516,4.516,4.516,11.864,0,16.38
C56.416,21.144,56.16,21.241,55.904,21.241z”/>
<path style=”fill:#7383BF;” d=”M51.693,19.241c-0.256,0–0.512–0.098–0.707–0.293c-0.391–0.391–0.391–1.023,0–1.414
c1.237–1.236,1.918–2.884,1.918–4.638s-0.681–3.401–1.918–4.639c-0.391–0.391–0.391–1.023,0–1.414s1.023–0.391,1.414,0
c1.615,1.614,2.504,3.765,2.504,6.053s-0.889,4.438–2.504,6.052C52.205,19.144,51.949,19.241,51.693,19.241z”/>
<path style=”fill:#7383BF;” d=”M4.094,21.241c-0.256,0–0.512–0.098–0.707–0.293c-4.516–4.516–4.516–11.864,0–16.38
c0.391–0.391,1.023–0.391,1.414,0s0.391,1.023,0,1.414c-3.736,3.736–3.736,9.815,0,13.552c0.391,0.391,0.391,1.023,0,1.414
C4.605,21.144,4.35,21.241,4.094,21.241z”/>
<path style=”fill:#7383BF;” d=”M8.305,18.966c-0.256,0–0.512–0.098–0.707–0.293c-1.615–1.614–2.504–3.765–2.504–6.053
s0.889–4.438,2.504–6.052c0.391–0.391,1.023–0.391,1.414,0s0.391,1.023,0,1.414c-1.237,1.236–1.918,2.884–1.918,4.638
s0.681,3.401,1.918,4.639c0.391,0.391,0.391,1.023,0,1.414C8.816,18.868,8.561,18.966,8.305,18.966z”/>
<rect x=”13.999" y=”6.999" style=”fill:#424A60;” width=”32" height=”42"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

There are also a lot of unused elements and useless declarations which need to be thrown out.

We’ll use SVGO for cleaning and optimizing our svg codes to a better and cleaner one which is much easier to manage.

Let’s install SVGO globally with npm package manager.

npm install -g svgo

Inside our project folder, enter the images folder and then type

svgo smartphone.svg

If it done correctly, you’ll see

smartphone.svg:
Done in 147 ms!
2.354 KiB — 45.8% = 1.276 KiB

With a simple command, we have optimized the svg codes and also the image dimensions are changed, now its file size is near the half of the original image.

Now open again smartphone.svg with a file editor and you see that the code is much better then before.

We also need to do a little reorganization and first of all detect the image parts nad add a comment for each of them.
Then add a <g> tag to group all the elements which compose the smartphone image without the phone ringing noises at the sides, it will be helpfull when we’ll add the html classes
Here is the one I made, you can just copy from below

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 59.998 59.998">
<g>
<!-- BASE -->
<path d="M42.594 58.999h-25.19a3.405 3.405 0 0 1-3.405-3.405V4.404A3.405 3.405 0 0 1 17.404.999h25.189a3.405 3.405 0 0 1 3.405 3.405v51.189a3.404 3.404 0 0 1-3.404 3.406z" fill="#e7eced"/>
<!-- HOME BUTTON -->
<circle cx="29.999" cy="53.999" r="3" fill="#fff"/>
<!-- SPEAKER & CAMERA -->
<path d="M29.999 4.999h-4a1 1 0 1 1 0-2h4a1 1 0 1 1 0 2zM33.999 4.999h-1a1 1 0 1 1 0-2h1a1 1 0 1 1 0 2z" fill="#424a60"/>
<!-- SCREEN -->
<path fill="#424a60" d="M13.999 6.999h32v42h-32z"/>
</g>
<!-- SECOND NOISE SYMBOL RIGHT -->
<path d="M55.904 21.241a.999.999 0 0 1-.707-1.707c3.736-3.736 3.736-9.815 0-13.552a.999.999 0 1 1 1.414-1.414c4.516 4.516 4.516 11.864 0 16.38a.993.993 0 0 1-.707.293z" fill="#7383bf" />
<!-- FIRST NOISE SYMBOL RIGHT -->
<path d="M51.693 19.241a.999.999 0 0 1-.707-1.707c1.237-1.236 1.918-2.884 1.918-4.638s-.681-3.401-1.918-4.639A.999.999 0 1 1 52.4 6.843c1.615 1.614 2.504 3.765 2.504 6.053s-.889 4.438-2.504 6.052a.993.993 0 0 1-.707.293z" fill="#7383bf" />
<!-- FIRST NOISE SYMBOL LEFT -->
<path d="M4.094 21.241a.997.997 0 0 1-.707-.293c-4.516-4.516-4.516-11.864 0-16.38a.999.999 0 1 1 1.414 1.414c-3.736 3.736-3.736 9.815 0 13.552a.999.999 0 0 1-.707 1.707z" fill="#7383bf" />
<!-- SECOND NOISE SYMBOL LEFT -->
<path d="M8.305 18.966a.997.997 0 0 1-.707-.293c-1.615-1.614-2.504-3.765-2.504-6.053s.889-4.438 2.504-6.052a.999.999 0 1 1 1.414 1.414c-1.237 1.236-1.918 2.884-1.918 4.638s.681 3.401 1.918 4.639a.999.999 0 0 1-.707 1.707z" fill="#7383bf" />

</svg>

Open the index.html file and paste the image svg code inside.
Let’s also add the head tag for the index.css link

<head>
<link rel=”stylesheet” href=”./index.css”>
</head>
<svg xmlns="
http://www.w3.org/2000/svg" viewBox="0 0 59.998 59.998">
<g>
<!-- BASE -->
<path d="M42.594 58.999h-25.19a3.405 3.405 0 0 1-3.405-3.405V4.404A3.405 3.405 0 0 1 17.404.999h25.189a3.405 3.405 0 0 1 3.405 3.405v51.189a3.404 3.404 0 0 1-3.404 3.406z" fill="#e7eced"/>
<!-- HOME BUTTON -->
<circle cx="29.999" cy="53.999" r="3" fill="#fff"/>
<!-- SPEAKER & CAMERA -->
<path d="M29.999 4.999h-4a1 1 0 1 1 0-2h4a1 1 0 1 1 0 2zM33.999 4.999h-1a1 1 0 1 1 0-2h1a1 1 0 1 1 0 2z" fill="#424a60"/>
<!-- SCREEN -->
<path fill="#424a60" d="M13.999 6.999h32v42h-32z"/>
</g>
<!-- SECOND NOISE SYMBOL RIGHT -->
<path d="M55.904 21.241a.999.999 0 0 1-.707-1.707c3.736-3.736 3.736-9.815 0-13.552a.999.999 0 1 1 1.414-1.414c4.516 4.516 4.516 11.864 0 16.38a.993.993 0 0 1-.707.293z" fill="#7383bf" />
<!-- FIRST NOISE SYMBOL RIGHT -->
<path d="M51.693 19.241a.999.999 0 0 1-.707-1.707c1.237-1.236 1.918-2.884 1.918-4.638s-.681-3.401-1.918-4.639A.999.999 0 1 1 52.4 6.843c1.615 1.614 2.504 3.765 2.504 6.053s-.889 4.438-2.504 6.052a.993.993 0 0 1-.707.293z" fill="#7383bf" />
<!-- FIRST NOISE SYMBOL LEFT -->
<path d="M4.094 21.241a.997.997 0 0 1-.707-.293c-4.516-4.516-4.516-11.864 0-16.38a.999.999 0 1 1 1.414 1.414c-3.736 3.736-3.736 9.815 0 13.552a.999.999 0 0 1-.707 1.707z" fill="#7383bf" />
<!-- SECOND NOISE SYMBOL LEFT -->
<path d="M8.305 18.966a.997.997 0 0 1-.707-.293c-1.615-1.614-2.504-3.765-2.504-6.053s.889-4.438 2.504-6.052a.999.999 0 1 1 1.414 1.414c-1.237 1.236-1.918 2.884-1.918 4.638s.681 3.401 1.918 4.639a.999.999 0 0 1-.707 1.707z" fill="#7383bf" />

</svg>

Phone ringing animation

Our phone element is rappresented by the tags warpped in the higher <g /> tag.
The first animation is a movement composed by 3, 10 degrees rotation starting from right.
Let’s add a smartphone class to the <g /> tag

<g class="smartphone">
...
</g>

Now open index.css and start declearing the smartphone class

.smartphone{
transform-origin: 50% 50%; /* RUN ANIMATION IN CENTER */
}

Now we create the animation which defines the movement.
We use @keyframes which let use define the three steps writing what the phone has to do in each step.
To rotate the phone 10 degrees use

transform: rotate(0deg);

So let’s define the keyframes animation and insert the code above with the correct degrees

@keyframes ring {
   /* start from original */
0% {

}
   /* rotate right */
20% {
transform: rotate(10deg);
}
   /* rotate left */
40% {
transform: rotate(-10deg);
}
   /* rotate right */
60% {
transform: rotate(10deg);
}
   /* return center */
80% {
transform: rotate(0deg);
}
}

And say to the smartphone class to execute this animation for 2 seconds infinitely

.smartphone{
transform-origin: 50% 50%; /* RUN ANIMATION IN CENTER */
  animation: ring 2s ease infinite;
}

Now launch index.html in your browser and you should see the smartphone animated.

Noises symbols animation

In the second act, we’ll animate the phone noise symbols on the upper side of the phone.
For this we may imitate the propagation of the sound, so waves which propagate fading far from the phone.

Let’s add some classes to the HTML file

<! — SECOND WAVE RIGHT →
<path d=”M55.904 21.241a.999.999 0 0 1-.707–1.707c3.736–3.736 3.736–9.815 0–13.552a.999.999 0 1 1 1.414–1.414c4.516 4.516 4.516 11.864 0 16.38a.993.993 0 0 1-.707.293z” fill=”#7383bf” class=”second-wave-right” />
<! — FIRST WAVE RIGHT →
<path d=”M51.693 19.241a.999.999 0 0 1-.707–1.707c1.237–1.236 1.918–2.884 1.918–4.638s-.681–3.401–1.918–4.639A.999.999 0 1 1 52.4 6.843c1.615 1.614 2.504 3.765 2.504 6.053s-.889 4.438–2.504 6.052a.993.993 0 0 1-.707.293z” fill=”#7383bf” class=”first-wave-right” />
<! — FIRST WAVE LEFT →
<path d=”M4.094 21.241a.997.997 0 0 1-.707-.293c-4.516–4.516–4.516–11.864 0–16.38a.999.999 0 1 1 1.414 1.414c-3.736 3.736–3.736 9.815 0 13.552a.999.999 0 0 1-.707 1.707z” fill=”#7383bf” class=”first-wave-left” />
<! — SECOND WAVE LEFT →
<path d=”M8.305 18.966a.997.997 0 0 1-.707-.293c-1.615–1.614–2.504–3.765–2.504–6.053s.889–4.438 2.504–6.052a.999.999 0 1 1 1.414 1.414c-1.237 1.236–1.918 2.884–1.918 4.638s.681 3.401 1.918 4.639a.999.999 0 0 1-.707 1.707z” fill=”#7383bf” class=”second-wave-left” />

</svg>

The waves propagation animation is made of two steps:

1 Translation far from phone, so the waves on the right will go to the left and the other ones on the left will go to the right. We’ll made a translation of 2px.

2 The waves will fade so we’ll start from 0 to 1, then at two third of the total time when the opacity is 1, we’ll fade away.

Let’s start with the fade animation

@keyframes propagation_right {
70%{
opacity: 1;
}
100%{
opacity: 0;
}
}
@keyframes propagation_left {
70%{
opacity: 1;
}
100%{
opacity:0;
}
}

and declaring them inside the waves classes

.first-wave-right{
animation: propagation_right 1.8s ease infinite;
opacity: 0;
}
.second-wave-right{
animation: propagation_right 1.8s 0.2S ease infinite;
opacity: 0;
}
.first-wave-left{
animation: propagation_left 1.8s ease infinite;
opacity: 0;
}
.second-wave-left{
animation: propagation_left 1.8s 0.2s ease infinite;
opacity: 0;
}

For each class we declared an initial opacity of 0 and an animation of 1.8 seconds which will repeat infinitely.
You see that in both the right and the left waves, the second ones ha also a 0.2s of delay.

Open index.html in your browser to see the results.

Now let’s create the translation animation

As I told after, we’ll make a translation of 2px far from the phone.
To make this, we need to manage the waves on the right separately from the waves on the left beacuse they start from different position and goes twoards differents position.
The waves on the right will start from a position of 2px backwards to its initial position, so 2px afterwards.
The left side is a reflection of the one on the right, so we’ll start from a position of 2px afterwards to its initial position, in this case we’ll go 2px backwards.

In index.css, let’s add the code to translate the waves to the both exiting propagation_right and propagation_left classes

@keyframes propagation_right {
70%{
opacity: 1;
}
100%{
transform: translateX(2px);
opacity: 0;
}
}
@keyframes propagation_left {
70%{
opacity: 1;
}
100%{
transform: translateX(-2px);
opacity:0;
}
}

Then declare the animation inside alle the waves classes

.first-wave-right{
transform: translateX(-2px);
animation: propagation_right 1.8s ease infinite;
opacity: 0;
}
.second-wave-right{
transform: translateX(-2px);
animation: propagation_right 1.8s 0.2S ease infinite;
opacity: 0;
}
.first-wave-left{
transform: translateX(2px);
animation: propagation_left 1.8s ease infinite;
opacity: 0;
}
.second-wave-left{
transform: translateX(2px);
animation: propagation_left 1.8s 0.2s ease infinite;
opacity: 0;
}

We made it! You animated your first svg using CSS. You can see that create simple but beautiful animation is very easy manipulating svg codes and dividing your image piece py piece.
This example is very basic but imagine what you can do with other CSS animation commands combined with SVG.