SVG Loader Challenge
Loading Spinners. We've all seen them; across the web and in our favourite apps. Popping up just as you were about to buy that thing that you like, or sign in to that app which you love.
Today I'm going to show you something a little different!
Recently there was a detailed case-study on cssanimation.rocks about the loading animation from bufferapp.com. It's a great article and I highly recommend reading it!
The loader is pure #awesome — not your usual spinning circle of doom — and it's done with svg
!
I challenge you!
After reading the article from cssanimation.rocks, my UX Designer colleage (@fearghal_) challenged me to do the same for our company; Lane Crawford.
Lane Crawford is a luxury fashion retail brand; it's supposed to symbolise elegance and prestige. So I wanted to create something which was refined, subtle and elegant. It should be asking you eloquently:
“Please wait one moment...”
instead of:
“oh crap, something's happening!!”
the result
I came up with this “rolling breath” animation; it incorporates the logo, and it doesn't scream at you. — I experimented with a couple of speeds and colours as you'll see below.
technicals
I am not familiar with svg
at all; I have never used it except for exporting from Illustrator. It looks very powerful and there's some amazing examples on Codepen.
What I gather through my time reading articles is that svg
appears to be well supported from IE10+, but it seems to have quite a few browser-quirks and difficulties associated with it when used as an image. However the power and flexibility of svg
, especially in-line cannot be denied! — I had a lot of learning to do!
how
So the requirements and general premise are as follows:
- Have an
svg
logo - Make sure the existing
svg
code is suitable/compatible - Separate each character as a path
- Apply a
css
animation to each character - Control animation with a wrapper class
logo
Luckily Lane Crawford already had an svg
version of their logo; which is used in the header of the site. Unfortunately, though, it was exported from software and the code was messy. So it needed some care before I could use it.
house-keeping
Firstly I opened up the .svg
file which was originally being included as a background-image
(read the css tricks article on why this is no good — it's to do with styling).
After taking a quick look, the file seemed a little strange (thanks, Adobe Illustrator) with the w
character being the first path (?), and the <svg ...>
tag being a mess.
I begin by cleaning up the <svg ... >
tag so it's usable, this means adding a proper id
and giving it a usable class
attribute, as well as sorting out the viewbox
and background
.
before
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="270px" height="65px" viewBox="460.275 388.445 270 65" enable-background="new 460.275 388.445 270 65"
xml:space="preserve">
after
<svg
version="1.1"
id="lanecrawford-logo"
class="logo lane-crawford-logo__svg"
viewBox="0 -4 236 64"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" >
In all honesty, as I mentioned before, I am a complete noob at svg, so I cannot tell you what all those attributes mean. I do know, however, (after reading the mozdev svg attribute reference) that certain things were unecessary (x="0px"
, y="0px"
). I also played around with the viewbox values after reading this article from vanseo design.
#icanteven handle the values of 460.275 388.445
— they make no sense — they were refactored to be integers which maintain the aspect-ratio of the logo; 0 0 236 64
.
character separation
Technically the characters were already separated, however I wanted them to be in the correct order (for sanity, code navigation, #reasons), and each character required a css
class so I could target it for animation.
<path class="l" d="M20.188..." />
<path class="a" d="M36.573..." />
<path class="n" d="M56.617..." />
<path class="e" d="M77.443..." />
<path class="c" d="M114.986..." />
<path class="r" d="M126.600..." />
<path class="a2" d="M136.202..." />
<path class="w" d="M161.558..." />
<path class="f" d="M190.896..." />
<path class="o" d="M193.951..." />
<path class="r2" d="M215.781..." />
<path class="d" d="M225.384..." />
The letters a
and r
occur twice, so they get a 2
suffix. I used class
instead of id
as this means I can have multiple copies of this logo on the page if needed.
styling & animation
firstly, since we are animating the paths up, we need the parent svg to allow the paths to overflow. And since we removed the fill="#2b2b2b"
attribute from each <path>
tag earlier, we must apply a fill to the paths — we will also animate the fill later.
.logo {
overflow: visible;
.path {
fill: #2b2b2b;
}
}
Then we must set up our animation:
@-webkit-keyframes breathe {
15% { fill: #d0b17b; }
21% { transform: translateY(-3px); }
}
I knew that I wanted a golden-sheen to go from left-to-right across the logo, I also wanted the letters to jump up fast, and then slowly fall back down, like a "sigh" or a "breath". So I have the golden colour appear at 15%
, and due to the defaults at 0%
and 100%
being our #2b2b2b
from earlier, it will appear fast and fade out slowly. The same goes for the translation at 21%
.
The value of -3px
is interesting, though; I played with a %
value, but it was moving each letter a different distance according to its width. However, because svg
scales; the -3px
actually changes depending on the size of the svg
image. It “feels” right.
Now to applying the animation with scss
:
$lanecrawford: "l","a","n","e","c","r","a2","w","f","o","r2","d";
Using the power of scss
I created a list containing all the class-names of the <path>
s in the svg
. This meant that I could run an @each
loop on the letters and calculate the animation-delay
s with math!
I apply the breathe
animation to the .logo
whenever it has the class .loading
:
.logo.loading path {
animation: breathe 2.6s ease infinite;
}
I now use the @each
loop to give each letter an animation-delay
so it plays on each time slightly later than the previous; making it appear to move from left-to-right:
@each $letter in $lanecrawford {
$i: index($lanecrawford, $letter);
$t: 0.03s * $i;
&.loading path.#{$letter} {
animation-delay: $t;
}
}
If the @each
loop syntax seems confusing, then I highly suggest reading the sass way's explanation on the subject.
controlling
In the codepen demo I simply use some jQuery
to apply the animation with a checkbox-toggle. However in the real world you'd apply it during ajax calls and page-transitions. -- jQuery
cannot apply css
classes to svg
, so it's applied with the native .classList.add()
method.
$( document )
.ajaxStart(function() {
$(".logo")[0].classList.add("loading");
})
.ajaxStop(function() {
$(".logo")[0].classList.remove("loading");
});
No matter when/why you apply the animation, it is triggered simply by applying the class of .loading
to the svg
element. #simples.
to conclude
This is a super-neat way of indicating to the user that something is happening, keeping things on brand, and not looking like a half-broken
jQuery
plugin is ‘acting up’.I'm not sure we will ever use this at Lane Crawford, but it was a nice experiment, and I am going to push for it.
In modern browsers it performs a lot better than an animated
.gif
.With a little javascript effort it's fairly easy to substitute it for an animated
.gif
in IE8 or lower.