Uncategorized

Animating a SVG image for the first time

Draw Inspiration logo

Last week I made the smallest website I’ve ever developed. Draw Inspiration is a single page website that allows users to print a random phrase for them draw. Phrases such as “icy pear”, “jealous butter” and “creepy popcorn”.

In making this website, part of the challenge was to keep it free of JavaScript but still make it more than a static page. One of the ways I wanted to do this was to animate the logo via CSS and SVG. It’s something Chris Wright covered at the recent CSSConf in Melbourne, so I gave myself 1 hour to get something up and running on this mini project.

This post covers a couple of the stumbling blocks I hit, and the (sometimes) dodgy solutions I took. There are many in depth videos and posts on this subject, by people much more knowledgable than me.

Creating the SVG image

Whilst I’d love to be able to write those path strings out, or create circles by hand, there’s no way I’m going to do that in real life. So I downloaded a copy of Inkscape. Inkscape is a bit like Freehand from 2001, and I love it! (I appologise if I’m doing Inkscape a disservice with that comparison, but I have fond memories of 2001 Freehand!).

Something to watch out for with Inkscape, by default the Inkscape SVG file includes a whole bunch of attributes that IE seems to get very grumpy about. I didn’t look too closely into this, but found that saving things out as a standard SVG made things run smoothly.

(Note: after writing this post I realised that Inkscape can often include transforms on the shapes you make. This can mess up your animations, especially if you’re relying on transforms. Whilst I’ve not been able to investigate this fully, I looked into why I didn’t have the problem with the Draw Inspiration logo and it was the grouping of the logo elements that removed the transforms.)

Embedding the SVG into the page

I wanted a workflow where I could save out the SVG file from Inkscape and have it automatically appear on the page, but I knew from Chris’ presentation that I’d need the SVG data embedded in the page (no background image or img tag). So I included it in my HTML file via PHP. Seemed like an easy solution, and got me through this project.

Resizing the SVG image with CSS

Secret ingredient to make the SVG image scale as you’d expect a standard img to is to include the “viewbox” attribute, without that your image will just sit in the corner taunting you.

Strange SVG height

I wanted to remove the SVG attributes for height and width, and hand that task over to the CSS. But I found problems with the height. It seemed as though the height was being defined by the view port of the browser. My work around for this was to use a parent element and position the SVG absolutely. Then pad the top of the container with a percentage that represented the aspect ratio I wanted. It’s a similar approach that’s quite popular with responsive video. I feel as though this was a bit of a cop out, and I overlooked something obvious. But again, it got me through.

Defining the animation

The CSS animation is defined as any CSS animation would be. For the logo I defined 2 animations; One moving the targeted element clockwise, and another moving it anti-clockwise. For easy assignment with the SVG I used Inkscape to create a group around “Draw” and “Inspiration” with a suitable ID on each, I then associated the IDs with the CSS.

When CSS animation isn’t available

The final stumbling block I had was with IE9. Whilst the CSS was associated with the SVG successfully, the animation didn’t work. My original setup with the CSS was to style the target elements with their initial state (e.g. make the opacity 0) then let the animation change those values.

There was a problem with this approach in IE9. IE9 understood the CSS but not the animation, and because of the initial state being set to 0 the logo vanished. If I set the CSS on the element to how I wanted the final state (opacity 1), then the element would flash for a split second as it waited for the animation to begin.

The solution to this was simple, define the element with how it should be displayed without any animation (opacity to 1) then set the “animation-fill-mode” to “both”. This allows the CSS properties of the animation to control the look of the element before and after the animation has played (e.g. animation starts at opacity 0 and finishes on opacity 1, so the element is set to opacity 0 before the animation begins).

A stand-alone example of the effect of animation-fill-mode

With the stars below, the desired effect here is to have a star that:

Animation keyframes

@keyframes fadeAndScale {
  0%   { 
    fill-opacity: 0;
    transform: scale(0.5);
  }
  66% {
    fill-opacity: 1;
    transform: scale(1.1);
  }
  100% {
    fill-opacity: 1;    
    transform: scale(0.5);    
  }
}

Star 1: Applying an animation with default settings

#star1 {
  animation: fadeAndScale 1s 0.5s 1;
}

This isn’t ideal as there’s a flash at the beginning of the animation. This is because we can see the non-animated CSS being applied before the animation begins.

Star 2: Specifying opacity as 0 on the CSS selector for the star

#star2 {
  animation: fadeAndScale 1s 0.5s 1;	
  fill-opacity: 0;
}

This isn’t ideal either, whilst there is no flash, the star disappears at the end so it doesn’t fulfil our requirements.

Star 3: Setting animation-fill-mode to both

#star3 {
  animation: fadeAndScale 1s 0.5s 1;
  animation-fill-mode: both;
}

Perfect, the star fades in then remains after the animation is finished. Be sure to put the animation-fill-mode after the animation though, some browsers will only obey the rule if it’s done in the correct order.

Ready to go

These steps got me through putting a SVG animation in place, with a graceful fallback to IE. Some of these steps I was happy with, others I feel were hacky work around from my lack of experience. I hope you can build on this and let me know of your approaches to make things even smoother.