In this post, I’ll show you how I went about coding an animated SVG (Scalable Vector Graphic) to convey to users of my web application mydevportfol.io that code is being written/generated for them while the app loads. I’ve really liked SVG icons for a while, and made a V8 engine style one for an application I built a few years ago, check that out here.
Update: This was done with SVG SMIL animations, which is being deprecated across most modern browsers. I've made an updated version using only CSS here
If you like this tutorial and want to learn more, I'll be making more very soon, subscribe with the form at the bottom of the page or click here for more info
This post, however, will be about my most recent creation, which I posted on Reddit’s /r/webdev last week and seemed to strike a chord. I received a few requests as to how I did it, so I thought I'd run through my process of how I built it, the tools and resources I used, and why I chose SVG in the first place.
I’ll also be making an updated version of this loader, but with cross-browser supported CSS, so subscribe to the blog if you’d like to see that too (I very rarely email you, promise). You could also keep an eye on my Twitter @cderm for updates, but I’m not as active there as I should be.
Why animated SVG?
I really enjoy animations, especially ones that are contextual. Whenever I’m working on a side project, an interesting loading animation is one of my indulgences I let myself give a little too much time to.
However, as a developer and not an animator, I don’t know the tools that designers use to make these funky animations. I wouldn’t even know where to start. That’s where SVG makes the most sense for me, because it’s code. It’s a text file that I can open and edit and re-load in the browser to observe the changes. It’s just like building a web page.
Another reason SVGs are awesome is that they’re vectors, so they look amazing on any screen size, there’s no pixels to distort like there would be in a GIF.
Cross-browser issues with SVG
Unfortunately, in terms of cross-browser compatibility, you need to be careful with what you use SVG animations for, as support isn’t great on any browser from Microsoft, and it’ll be deprecated in a future version of both Chrome and Opera. Check out SMIL animations on caniuse.com. However, fear not as we can usually convert these SVGs to GIFs to act as a fallback.
Depending on the type of animations you need, CSS animations are widely supported, I’ll be writing a post on recreating this loader with some extra tweaks, all in browser-compliant CSS, so stay tuned for that in the coming weeks.
Whenever I need some sweet images or animations for inspiration, I turn to Dribbble. There’s an abundance of talented designers there who love to share their work. Sometimes the animations can be overdone and somewhat unrealistic, but I’m yet to leave the site without a better idea of what I want to create.
Below are some of the images I used for inspiration.
The end goal
If you’ve seen the Reddit post, you’ll know what I’m going for, but for reference, here’s what I had in my head at the time. Keep in mind that the animation below is a GIF, as WordPress doesn’t like hosting SVGs. The SVG version over on mydevportfol.io doesn’t “reset” like the animation in the GIF version does.
I wanted the animation to convey to the user that the application is “coding” them a website, so I thought left-to-right animated rectangles flowing down the screen would work well.
To make things easier, let’s break the animation down. It’s basically just different colour rectangles with border radii, expanding from left to right, and then scrolling upward after a certain delay.
For the purpose of this post, I’ll seperate the animation into two main parts. The first part will deal with getting the rectangles to expand from left to right, showing one line after another. The second will deal with the scrolling motion.
1 – Getting Started with SVG
As I mentioned earlier, SVG is just code. I don’t usually start a website by typing out the HTML from scratch, I use a boilerplate, or a generator to save time. In this case, I want to use an image editor to get started, providing me with the “boilerplate” SVG code, and then I can edit from there.
I usually use Sketch for this, but if you don’t have it, you can use any of the free online tools. I used editor.method.ac for this tutorial, as it’s clean and simple to use.
All we need to do is draw one rectangle. You could go a lot further here and draw as much as you like, but I personally prefer just getting my hands on the code early. I like to use Codepen for these types of small projects, as we can see code changes in real time. Save the SVG file from the image editor, open it up, and copy-paste the code into a new Pen.
2 – Copy-pasting the SVG code to codepen to get started
If you’re not familiar with what is actually inside an SVG, fear not. It’s relatively straight-forward and very similar in syntax to HTML. Now’s a good time to have a quick look at the elements in an SVG.
<g> tags are “groups”, and we’ll use them to house a block of elements that we want to animate as one.
<rect> elements are rectangles, with attributes we can modify such as stroke (border), fill etc. Groups, rectangles and animations can all be given an “id”, just like HTML divs, which we will use to animate and control timing later on.
3 – Cleaning things up a little
In the above pen we’ve given the SVG a more reasonable height and width, and we’ve removed the background element that the editor added for us as we don’t need it for our animation. We’ve also removed the stroke attributes from the rect element, we don’t need them either.
We’ve also given the group and the rect elements id’s. This is mainly just a personal choice so I know what element I’m working on at any one time. The group “group1” is the
<g> element that will group together all of the left-to-right animations.
I’ve also moved the line to top left of the viewport, and given it a width. We’ll remove the width in the next pen as we’ll want to animate the width from zero.
4 – Our first animated SVG!
Ok, here we’ve added the code to animate the #line1 rect from 0 to 350px wide. The first thing to notice is that we added the
<animate> element within the
<rect> element, before its closing tag.
Then, we added some attributes to the
<animate> element. Let’s take a look at the attributes and what they mean
attributeName: The name of the attribute we want to animate. In this case, we want to animate the width.
from, to: The values across which we want the attribute to animate from and to. In our case it’s from 0 to 350.
dur: The duration of the animation. we can make it as fast or as slow as we want. In this case I think 0.3s works well.
fill: This determines the behaviour of the animation when it completes, “freeze” means that the animation doesn’t loop, which is what we want in this case.
id: This is the unique id for the animation, not for the element that you want the animation to apply to. We need to give it a unique identifier because we’ll be referencing this animation from within other animations. You’ll see how that works in the next step
5 – “Chaining” SVG animations
In this pen, we added another
<rect> element or “line of code”, and an accompanying animation to animate its width. We want this animation to start when the first one finishes. To do this, we add a “begin” attribute to the animation, and for the value we add the ID of the first animation, followed by “.end”. So, in our case we get begin=”line1_anim.end”. And just like that, our second animations starts when our first one ends.
One other thing to notice about this pen is the “indentation” of #line2. SVGs are based on a grid system, so by adding x=”30″ and y=”30″ to the element, it sets its position in 30px to the right, and 30px down.
6 – Finishing out our first group
Ok so here we’ve just followed the pattern started in the previous step and filed out all the lines we need for the first group. Each line begins to animate when the previous one finishes. We use the x and y attributes to position the
<rect> elements as we need, indenting in and then back out as a normal typical block of HTML code would.
Remember earlier how I mentioned how we’ll break the entire animation into two parts? This wraps up that first part, where our “lines of code” are all animated in and ready to be “scrolled”
It’s starting to look like our goal 🙂
7 – Simulating the scroll effect
The first part to simulating the croll effect is to animate the entire #group1 element upwards using an
animateMotion element. This element is used to move elements, as opposed to just animating their attributes. In the pen above we’ve added one of these elements, which starts after all of the lines are drawn, lasts two seconds and loops forever by using repeatCount=”indefinite”.
8 – Adding new “lines of code”
This next step was a bit tricky. Basically what we’ve done is duplicate most of the code from our first group, and made a new group called #group2. The only difference is we’re starting the animation for #line9 (the first line of the new group) after the last line (#line8) has finished. However, and this is the magic part, we also want to start the animation for #line9 1.75 seconds after it itself has completed. Otherwise, it will just run once and never again. So, as an attribute on #line9’s animation, begin will look like: begin=”line8_anim.end;line9_anim.end+1.75″.
Notice the semicolon, this allows us to set multiple start points for an SVG animation. We’re telling the animation to run when #line8_anim ends, but also 1.75 seconds after #line9_anim ends too. It’s tricky, but it works.
You’ll notice now, however, that we still have a little cleaning up to do.
9 – The final touchesIn the previous pen you could see the lines below were already there before being “re-drawn”. In this pen the only change is to adjust the height of the viewbox to 240px so that those lines are hidden.
Coming in version II
When I posted this on Reddit, I didn’t expect it to be received as well as it was. I just wanted to share what I’d wasted a Friday night doing. I’m really glad I did though, since I received some fantastic feedback.
An honourable mention to /u/phpdevster and /u/designerandgeek who both had some fantastic suggestions for improvement in this comment thread in /r/webdev.
I’ll be feeding those comments, as well as many more from the post into version 2, which I’m going to try in CSS only for more cross-browser compatibility.
Resources I used for this post