Building Animated SVG Banners
I've been reading David Walsh's blog for years. The tips and tutorials he shares have helped me fix a lot of problems. I love that I get to support him now by advertising TrackJS on his site. Plus, I get a chance to build some cool SVG animations!
I'm not a designer or a marketer by trade. I'm a software developer, but as an entrepreneur I end up doing a bit of everything. I spent a lot of time sketching and googling to figure out how this works. I'd like to share what I've learned about designing and building animated SVG ads, like this one right here:
Advantages of SVG
SVG, or Scalable Vector Graphic, an XML-based structure that defines the shapes, lines, and colors of an image in such a way that it can be viewed at any size and still retain a crisp look. SVG is not well suited to display photography images, but it is excellent for drawings, text, and shapes.
It is also a fantastic platform for animations, as the same CSS technologies that drive animation on the web can also animate the markup for SVGs.
SVG images are well supported by web browsers today, although Internet Explorer 9 and earlier may have some problems (big surprise).
The Spec
David gave us a standard banner spot at the top of content. The ad should be responsive from mobile to desktop sizes, up to the standard banner dimensions of 728px by 90px.
Our ad needs to quickly describe TrackJS and how we can help. We monitor your JavaScript for bugs and give you awesome error reports when they happen. We need to figure out a way to say this concisely and with a bit of humor.
We also need to be a responsible advertiser:
- Clearly differentiate from the page.
- Do not block or slow the content from loading.
- Do not distract the visitor from the content.
My First Animated Ad
I wanted to build something that plays off of "bugs". We had some Adobe Illustrator assets of a bug getting squashed for an earlier sticker that we can probably reuse. Maybe the bugs can fly over the ad and get squashed by the "free trial" button.
I started fumbling my way around the internet to figure out how to make this happen. I defined an SVG
element in an HTML file and started learning. I set the height and width for the banner. Double that for the viewBox
, which is like the window into the drawing, so that everything looks sharp on high-density displays.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="720px" height="90px" viewBox="0 0 1456 180" style="background-color:#2c3237"></svg>
And now I had a nice grey box! Small accomplishments.
Most of the ad was going to be static: our logo, description, and tagline. I drew those with Photoshop in the fonts and colors I wanted and exported it as an SVG. I copied the shape definitions that came out of that and pasted it into my SVG element as a new path.
I made a button too, but I exported that as a separate SVG so that I could manipulate it separately later. I had something like this:
<svg xmlns="http://www.w3.org/2000/svg"> <path class="tjs-logo" d="..."/> <path class="tjs-button" d="..."/> </svg>
Animating SVG With CSS
Now to make some animations. I exported the bug animation from Adobe Illustrator as an SVG and grabbed the path data. I wanted to have a few bugs, but I didn't want to have multiple copies of the path data, as it was quite large. Fortunately, I found the SVG Symbol element, which lets us define shapes that can be instantiated many times. Just what I needed.
<defs> <symbol id="tjs-bug"> <g class="tjs-bug"> <path d="..." /> <path d="..." /> <path d="..." /> </g> </symbol> </defs>
Symbols get instantiated with the <use>
element, which I created three of. I added a transform to each of them to reduce them down to 0% size so that they wouldn't be visible on the page right away.
<use class="tjs-bug-1" xlink:href="#tjs-bug" transform="scale(0)" /> <use class="tjs-bug-2" xlink:href="#tjs-bug" transform="scale(0)" /> <use class="tjs-bug-3" xlink:href="#tjs-bug" transform="scale(0)" />
I'd done a few things with CSS Animations, so it was great that you can embed CSS directly inside the SVG markup. You just need to surround the rules with the CDATA syntax so that it continues to be valid XML (although most browsers are very forgiving of this).
I defined a CSS keyframe
for each of the three bugs that had the bug "fly" across the ad. Using a midway stop point in the keyframe and the ease
tween to make it feel like the bug stopped and landed before moving on. Then finally attached the keyframe to the class name on each use element.
<svg …> <style type="text/css"><![CDATA[ @keyframes flight-1 { 0% { transform: translate(-100px, -40px) scale(2.5) rotate(105deg) } 66% { transform: translate(500px, 0) scale(2.5) rotate(85deg) } 100% { transform: translate(1800px, -60px) scale(2.5) rotate(85deg) } } .tjs-bug-1 { animation: 1.8s flight-1 1s forwards ease; transform: scale(0) }
]]></style> <...> </svg>
I used the same flow to export a bug squash drawing from Adobe Illustrator and add it to the SVG. I timed another keyframe animation to have it appear and grow just as the button slides down from the top. The whole thing happens fast enough that it feels like the button squashes one of the bugs.
Here's the final result from it. This version below is not minified or obfuscated, so you can pop-open your dev tools and see all the details of the final implementation.
The Next Generation
Building the first one was a lot of fun, and I learned a lot about SVGs along the way. This ad has been running for several months but now it's time for an update. This time, I wanted to tell a story that recognizes that JavaScript creeps into our apps in all sorts of unexpected ways, and when it fails it can have nasty consequences. JavaScript Happens.
<object data="animated-happens.svg" type="image/svg+xml" style="width:100%;pointer-events:none;"></object>
For this ad, I worked with a talented illustrator to bring it to life. Spelunking through his code, I saw two important patterns that I had missed.
1. Using <animate> Elements instead of CSS
Rather than using a large, embedded set of CSS rules to handle animating all the different elements, he included <animate>
and <animateTransform>
elements nested inside of the drawings to be animated. I can instantly see the utility of doing this, as I spent lots of time scrolling back and forth during my original development tweaking the timing.
Keeping the animation rules close to the objects to be animated is a huge win for productivity during the development, and any future maintenance that might be needed.
2. Referencing the SVG as an <object>
Rather than including the SVG markup directly in the HTML document, as I had done, he had referenced an external SVG file using the <object>
element. This allows for the SVG markup to be externally included and referenced in the DOM.
<object data="animated-happens.svg" type="image/svg+xml"></object>
If we had referenced the SVG file using an <img>
element instead, this creates a strict boundary between the SVG and the DOM. The implication of this is that the "load" event will not trigger after the SVG is loaded into cache, and the animation will only ever play once.
Wrapping Up
SVG animations are cool. They load fast, have lots of powerful options, and are widely compatible. When used responsibly, we can use them to tell short, impactful stories, then get out of the user's way.
The web gets better every day. When it breaks, I'm so proud to be part of making it better and fixing its bugs. I'd love to help you too, grab a totally free, no credit card or anything, trial of TrackJS today.
About Todd Gardner
Todd Gardner is a software entrepreneur and developer who has built multiple profitable products. He pushes for simple tools, maintainable software, and balancing complexity with risk. He is the cofounder of TrackJS and Request Metrics, where he helps thousands of developers build faster and more reliable websites. He also produces the PubConf software comedy show.
Nice! I was wondering when svg will be a standard on banners and even on blogging industry. Thank you Todd and David for this great article.