SVG Animations - Seriously Very Good

Posted by Julia Mitchelmore on 4 December
Julia Mitchelmore

Imagine the entire web was just static. Filled in by nothing but words, information and meaningless black and white text. We would all spend a lot less time using the internet.

Thankfully we don’t. Instead the internet is a vibrant and expressive place where we immerse ourselves each day in an endless variety of unique experiences. Animation and movement are the visual language through which we catch our audience’s attention. We apply the finesse to our words and breathe life and meaning into our work.

Scalable Vector Graphics (SVGs) are a fantastic tool for every seasoned animator. Unlike traditional image formats they are built using vector paths that save into workable, writeable code. Their output is a complex XML-based structure consisting of tags like <path>, <circle>, <rect> and so forth. To these you can assign properties and masterfully take control of your SVG graphics.

SVGs are vector paths so they scale consistently without any nasty pixelation. They can be assigned fill colours, stroke colours and even border styles. Animating them is easy using CSS3 or SMIL (Synchronised Multimedia Integration Language) and brings movement and life to an otherwise static and lifeless shape.

Here’s one I prepared earlier to highlight the possibilities that can be achieved simply through the use of SVGs and animation. It is built entirely in HTML5/CSS3 using vector shapes from Vecteezy, which I then edited and exported using Sketch.

See the Pen Blueprint Playground by Julia Mitchelmore (@juliamitchelmore) on CodePen.

Note: Can't be viewed in Firefox because the browser doesn’t provide support for some of this cool stuff and the playground just ends up looking weird :(

  1. Outlines
    An SVG’s stroke is the border of its shape. The stroke can have multiple properties such as weight and colour. Create a tracing effect using the dashed feature of a stroke and the dash-array, dash-offset properties. These indicate length of dash and dash starting point along the edge.The trick is instead of having many short dashes, we make the stroke-dasharray value longer than the border of the shape. Then we animate the stroke-dashoffset from the stroke-dasharray value down to 0. The longer the border of the path, the higher the initial values of stroke-dasharray and stroke-dashoffset needed.ferriswheel
    <span class="s4"><span class="s4">path {
     <span class="Apple-converted-space">    </span>stroke-dasharray: 3000;
     <span class="Apple-converted-space">    </span>stroke-dashoffset: 3000;
     <span class="Apple-converted-space">    </span>animation-name: draw;
    </span></span>@keyframes draw {
     <span class="Apple-converted-space">    </span>to {
     <span class="Apple-converted-space">        </span>stroke-dashoffset: 0;
     <span class="Apple-converted-space">    </span>}
  2. Fill
    Each path can be filled with colour - this feature being a major attractor to using the SVG format. Fill can be given an opacity between 0 (transparent) and 1 (opaque). This allows us to animate from no-fill to fill.swings

    Note: Elements which overlap one another (eg. the axis on the carousel above) don’t want the lines of any paths behind. To avoid this all elements first get filled in with the document’s background colour and only after with a solid colour. This is achieved by chaining three animations together.

    <span class="s4">animation-name: draw, fillBackground, fill;

    As for the colour randomness on the page: this is a little Sass mixing I built myself. It takes an input colour and returns a set of random colours within a certain range. You can check out Sass Colour Range on Github.

  3. Timing
    Originally when I built the playground, each section was dealt with individually - building it and then filling it in. Different sections were shown using Javascript’s timeout, changing the display property of each element from none, triggering the animation to start. The end result was messy so I instead used CSS’s animation-delay property to trigger specific start times for each animation. I then created an ‘end’ variable used to trigger the fill for every part of the playground simultaneously.
    <span class="s4"><span class="s4">$end-fill: 10s;
     <span class="Apple-converted-space">    </span>animation-name: draw, fill;
     <span class="Apple-converted-space">    </span>animation-delay: 0s, $end-fill;
     <span class="Apple-converted-space">    </span>animation-name: draw, fill;
     <span class="Apple-converted-space">    </span>animation-delay: 4s, $end-fill;

    Each animation can also have a timing function applied to it, changing the rate of change throughout its duration. Most elements are animating with a linear timing in order to create a more uniform and monotonous look. However certain elements have subtle changes.

    One such is the swing, which uses an ease-in-out function to make the swing seem like it’s hovering at the peak of each swing before gradually speeding towards the trough.

    <span class="s4">animation-timing-function: ease-in-out;</span>
  4. Rotation
    There is lots of rotation going on in the playground, each to varying degrees. The carousel and each carriage rotates a full 360°. The seesaw and swings move slightly less. Rotation of the swings is limited to the X-Axis so that it appears to swing back and forth rather than in a circle. Because the swings are drawn hanging down whereas their rotation moves from -33° to 33°, an animation has been included to first pull the swing back. This animation is called only once using animation-iteration-count, while the swinging motion is on an infinite loop.
    <span class="s4">animation-name: swingback, swing;</span>
    <span class="s4">animation-iteration-count: 1, infinite;
    animation-delay: 0s, 1.1s; </span>
  5. Bouncing
    There are two parts to the bouncing ducks - the spring and the duck itself. While it looks like a simple up and down motion, these two parts are distinctly different. The spring has to collapse into itself while the duck stays the same shape and doesn’t scale. Therefore the spring has its own animation using scale-Y, but the duck itself uses translate-Y to move up and down. A minor annoyance - scale and translate use different methods of determining distance (translate calculates by pixels, scale by a part of 1).ducks
    <span class="s4"><span class="s4">@keyframes spring {
     <span class="Apple-converted-space">    </span>from
     <span class="Apple-converted-space">    </span>{
     <span class="Apple-converted-space">        </span>transform: scaleY(1);
     <span class="Apple-converted-space">    </span>}
     <span class="Apple-converted-space">    </span>to
     <span class="Apple-converted-space">    </span>{
     <span class="Apple-converted-space">        </span>transform: scaleY(0.8);
     <span class="Apple-converted-space">    </span>}
    </span></span>@keyframes duck {
     <span class="Apple-converted-space">    </span>from
     <span class="Apple-converted-space">    </span>{
     <span class="Apple-converted-space">        </span>transform: translateY(0);
     <span class="Apple-converted-space">    </span>}
     <span class="Apple-converted-space">    </span>to
     <span class="Apple-converted-space">    </span>{
     <span class="Apple-converted-space">        </span>transform: translateY(10px);
     <span class="Apple-converted-space">    </span>}
  6. Sliding
    CSS doesn’t have a great deal of support for motion paths - this is still an experimental property in Chrome only. Instead of using CSS to achieve the motion of the ball sliding down the slide, I’ve used SMIL’s animationMotion property as a child node of the circle path. Path of motion is determined using the path attribute on animateMotion.
    <span class="s4">&lt;animateMotion
        path="M197.125,297.636719 C197.125,297.636719 319.5625,276.726563 385.351562,333.406251 C451.140625,390.08594 452.066406,558.484368 502.964844,571.152331 C553.863281,583.820293 634.578125,567.597656 677.324219,479.175775"
        dur="2s" begin="16s" repeatCount="indefinite"
        calcMode="spline" keyTimes="0;1"
        keySplines="0.755, 0.05, 0.855, 0.8"/&gt;

    Much like CSS animations, SMIL’s animateMotion takes specifications for animation-duration (dur), animation-delay (begin), and animation-iteration-count (repeatCount).

    In order to create an animation-timing-function three properties are needed - calcMode, keyTimes and keySplines. ‘Spline’ is the SMIL keyword to indicate a custom bezier which is then defined in keySplines. The keyTimes attribute is also required to determine the duration of the function. This timing function creates the slow-to-fast sliding motion as the ball slips down the slide.


    Both CSS and SMIL animations don’t allow for a delay between repeats of an animation. Therefore preventing the ball sliding continuously down the slide without a break requires an additional CSS animation. This animation runs for 5x the length of the ball rolling animation, and then shows the ball for 20% of that time. With a 2-second animation on the ball there is then an 8 second gap before the ball is shown rolling again. The ball is actually continually rolling the entire time, just not visibly to the viewer.

    <span class="s2">.ball {
     <span class="Apple-converted-space">    </span>animation: slideHide 10s linear infinite;
     @keyframes slideHide {
     <span class="Apple-converted-space">    </span>1%, 20% {
     <span class="Apple-converted-space">        </span>opacity: 1;
     <span class="Apple-converted-space">    </span>}
     <span class="Apple-converted-space">    </span>21%, 100% {
     <span class="Apple-converted-space">        </span>opacity: 0;
     <span class="Apple-converted-space">    </span>}

CSS and SVGs are amazingly cool and incredibly powerful. With an underwhelmingly few lines of code you can break away from the cold, lifeless and even Orwellian nightmare of a motionless information super highway.

Despite these techniques being capable of producing drastically complex animations they’re also a fantastic way to apply polish to the tiniest of details throughout your work. You can sweat the details, without sweating the details and build an experience that your users will absolutely love to use. Look out for more of these neat little animations throughout our blog posts and across our website!

Topics: Development, Web, Experimental