SVG path’s are really awesome! And its versatility is what makes them even more impressive and useful for creating engaging animations.
In this tutorial we’ll be creating an eye catching animation, just using SVG paths and CSS transitions. To make things easier, we will also be using Pug and Sass, HTML and CSS preprocessors respectively. They will allow us to write much cleaner and more organized code, and also help with maths.
The animation we’ll be creating, has been inspired by this shot on Dribbble, by Clément Brichon. More specifically, we’ll be building something like this:
The main idea to get it working in the browser, is to have a background image, and then the entire black background is composed by SVG paths that we can animate to achieve an effect similar to the animated prototype.
Important: Please note that we are using some techniques that are not fully supported by all browsers. The final demo has been tested successfully in Chrome, Opera and Firefox (Linux).
Getting started with SVG paths drawing
To implement the animation, we will use the technique of “drawing” SVG paths. You can get started with the technique reading any of this great tutorials:
However, this time we will be using a variation of this technique, so that we will not animate the stroke-dashoffset
property, but the stroke-dasharray
. This will provide us a little more flexibility to draw the paths in the direction we want. If you want to know more about how this technique works, you can read this tutorial that I wrote some time ago, where it is described in detail (section “Drawing from begin to end”).
Generating the HTML with Pug
Let’s start by saying that Pug (formally known as Jade) is a high performance template engine, heavily influenced by Haml and implemented with JavaScript for Node.js and browsers. If you want to learn more about it, here is a nice tutorial.
Pug’s syntax is pretty straightforward, and we will be using just variables and mixins, leaving HTML markup as is. So you may not need to read a tutorial to understand the following code :)
//- Background image and button
<div class="background-image"></div>
<button>Toggle Animation</button>
//- Some variables to help with maths
- var circlesNumber = 5;
- var strokeWidth = 150;
- var radius = 100;
- var width = radius * 2;
- var height = radius * 2;
- var left = width / 2;
- var top = height / 2;
//- The main function to build a circle (SVG path)
//- Formula taken from this answer: http://stackoverflow.com/a/10477334
mixin circle(className)
<path class="#{className}" d="M #{left} #{top} m -#{radius} 0 a #{radius} #{radius} 0 1 0 #{radius * 2} 0 a #{radius} #{radius} 0 1 0 -#{radius * 2} 0"/>
//- Center circle
<svg class="svg-center" width="#{width}" height="#{height}">
+ circle('path-center')
</svg>
//- Reset some variables to build the other circles
- width = 10000;
- height = 5000;
- left = width / 2;
- top = height / 2;
- radius += strokeWidth / 2 - 1;
//- Very big SVG
<svg class="svg-borders" width="#{width}" height="#{height}">
//- Build the circles, increasing the radius at each iteration
while circlesNumber--
+ circle('path-borders')
- radius += strokeWidth - 1;
</svg>
Basically, what we have done here is to generate several SVG paths as circles. Then with a little style, we will make the stroke of each path very thick, covering the whole screen as we want.
Drawing the SVG paths
Now that we have our markup ready, we can start animating the SVG paths with CSS. So without further ado let’s see the code needed to get it working:
// Same variables used in HTML
$circlesNumber: 6;
$strokeWidth: 150;
$radius: 100;
// PI value (approximately)
$pi: 3.15;
// A big length
$maxLen: 10000;
// Loop to generate convenient stroke-* values
@while $circlesNumber > 0 {
// Calculate the SVG path length (approximately)
$currentRadius: $radius + ($circlesNumber) * $strokeWidth - $strokeWidth / 2;
$len: 2 * $pi * $currentRadius;
// Draw the entire path
.path-borders:nth-child(#{$circlesNumber}) {
stroke-dashoffset: $maxLen;
stroke-dasharray: $maxLen 0 $len;
}
.open-state {
// "Erase" the path, with alternating direction
.path-borders:nth-child(#{$circlesNumber}) {
@if ($circlesNumber % 2 == 0) {
stroke-dasharray: $maxLen 0 0;
} @else {
stroke-dasharray: $maxLen $len $len;
}
}
}
// Next iteration
$circlesNumber: $circlesNumber - 1;
}
To make things clearer, let’s have a look a the CSS output just for one iteration:
.path-borders:nth-child(2) {
stroke-dashoffset: 10000;
stroke-dasharray: 10000 0 2047.5;
}
.open-state .path-borders:nth-child(2) {
stroke-dasharray: 10000 0 0;
}
That’s all the CSS needed to get a single SVG path working! The complexity in the SCSS code is associated with calculating these values automatically, avoid repeating code and facilitate maintenance.
Adding some animation details
To get the most of our animation, we need to pay attention to details. So, let’s apply some more effects to complement the drawing animation.
.open-state {
// Scaling down the image
.background-image {
transform: scale(1);
}
// Rotating SVG paths (except the center circle)
.svg-borders {
transform: translate(-50%, -50%) rotate(90deg);
}
// Animating the center circle
.path-center {
stroke-width: 400px;
}
}
Finishing
And we are done! With some more style touches we should get the desired effect. The live version is here. Enjoy it!
Please note that to focus the tutorial on how to build and animate SVG paths, some details in the code have been omitted. As always, we invite you to get the full code on Github, and we really hope you find it useful!