Learning SVG animations by “drawing” the Square logo

Disclaimer: I am an engineer at Square. This is something I did for fun on my own time. Any opinions are my own and do not necessarily reflect those of my employer.

Recently, I went to a SFHTML5 meetup and saw Sarah Drasner do a talk on SVG (Scalable Vector Graphics) animations. One slide that stuck out was a demo of an SVG appearing to draw itself. So, for a short weekend-bound project, I decided to learn how to work with and animate SVGs.

As an engineer at Square, I was naturally drawn to the company logo. It is simple, and it is rendered with SVG all over Square’s public websites. I set out to do a self-drawing animation of the logo. Here’s the final result:


At the most basic level, SVGs are XML documents that declare shapes and paths. The simplicity of the specification belies its expressiveness; developers, designers, and artists use this technology to create graphics ranging from simple logos (like the Medium logo in the corner) to complex animations. And because SVGs are defined with unitless coordinates instead of pixels, they are technically infinitely scalable.

My first stop was in Mozilla’s SVG tutorial. It is a very good introduction.

My second stop was grabbing the SVG for the Square logo. That’s when I realized that this wasn’t going to be 1-hour project.

<svg id="logo__filled" class="animate" aria-labeledby="square-logo-title square-logo-desc" role="img" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg">
<path d="M36.65 0h-29.296c-4.061 0-7.354 3.292-7.354 7.354v29.296c0 4.062 3.293 7.354 7.354
7.354h29.296c4.062 0 7.354-3.292 7.354-7.354v-29.296c.001-4.062-3.291-7.354-7.354-7.354zm-.646
33.685c0 1.282-1.039 2.32-2.32 2.32h-23.359c-1.282 0-2.321-1.038-2.321-2.32v-23.36c0-1.282
1.039-2.321 2.321-2.321h23.359c1.281 0 2.32 1.039 2.32 2.321v23.36z"
role="presentation">
</path>
<path d="M17.333 28.003c-.736 0-1.332-.6-1.332-1.339v-9.324c0-.739.596-1.339 1.332-1.339h9.338c.738
0 1.332.6 1.332 1.339v9.324c0 .739-.594 1.339-1.332 1.339h-9.338z"
role="presentation">
</path>
</svg>

Despite the logo being very simple—after all, it’s just a couple of concentric rounded squares—its SVG representation was composed of two very complicated paths containing Bezier curves. I never encountered Bezier curves in either my formal education or my practical experience; to say the least, this intimidated me.

My third stop was looking up how the SVG self-drawing effect worked. I was surprised to find that it’s actually really simple but clever. In essence, if you have an outline of your shapes, you start by turning the outline into dashes that are as long as the outline itself, moving the single dash completely out of view, and then using a CSS animation that smoothly moves it completely into view.

Aside: searching for information about SVG animations may turn up articles on SMIL, a specification for native SVG animation. SMIL is supported in a few browsers, but it is on its track to deprecation and will never be supported in IE. Use CSS animations instead.

This technique only works if you are working with strokes. The Square logo SVG—clearly produced by a non-human toolset that optimized for precision and rendering speed—does not have any strokes. I didn’t have substantial experience with SVG tooling, so I didn’t know of a method to inspect those <path> elements or to create an outline from them.

I settled with manually creating <rect> elements that very closely matched the outline of the paths. It involved a lot of trial and error. Fortunately, the combination of Chrome developer tools and CodePen made it very easy for me to adjust the different parameters of the outline and see the effects of those changes instantly. I managed to get something very close (you can toggle the outline by clicking the shape).

And from there, it became just a matter of finding the lengths of the outline elements and adjusting their respective animation properties to be aesthetically pleasing. To top it off, I fade in the full original logo once the logo outline finishes drawing itself. The final result is the Pen at the top of the article.


As a digression, the strangest challenge was implementing the restart button. It is reasonable to believe that the browser would provide either a CSS or JavaScript method to restart a CSS animation. Of course, as with much of the frontend development, that would be too straightforward.

The obvious approach of simply removing and re-adding the class with the corresponding animation rule does not work. What does work is, between removing and re-adding the animation class, adding a small delay or forcing a DOM reflow. There are a number of strange workarounds to achieve this. I chose the method of accessing the layout width of the element:

element.classList.remove(animateClass);
void container.offsetWidth;
element.classList.add(animateClass);

Many articles, including the one linked above, do not mention this important subtlety: unlike DOM elements, SVG elements do not follow the CSS box model or layout rules. The offsetWidth property does not exist on on SVG elements. However, we can work past this by wrapping the root <svg> element in a <div> and forcing a DOM reflow on the parent <div>.

function resetAnimationObjects(container, animateClass) {
const animated = container.querySelectorAll(`.${animateClass}`);
animated.forEach(function(element) {
element.classList.remove(animateClass);
});

void container.offsetWidth;
  animated.forEach(function(element) {
element.classList.add(animateClass);
});
}
// Assuming we did a <div class='container'><svg></svg></div>
const container = document.querySelector('.container');
resetAnimationObjects(container, 'animate');

This is where I am expected to say something profound to conclude this first Medium writing piece, but I apologize for the disappointment.

Aside from that, this was a fun short project for a weekend, and I’m glad that I got to learn quite a lot about SVGs and CSS animations from this.

Show your support

Clapping shows how much you appreciated Daniel Ge’s story.