Using gifs for UX animations

Ian Sibner
3 min readSep 12, 2016

--

TL;DR— I needed a way to programmatically control gif animations, so I built sibgif, which makes it easier to incorporate gifs into a site’s UX.

These days, gifs are the most common format for animated images. Their compression isn’t particularly great, but they work everywhere and do a pretty good job of compressing simple images (especially those which use few colors, like logos and simple animations). So when I was working on the Root Tech website with Jeff Wang, it made sense that he sent all the animations for the site in GIF format. There was just a slight issue: the design called for the animations to respond to a visitor scrolling down the page. As you scrolled down, the lamp would plug itself in, the lightbulb would turn on, et cetera. If you scrolled back up, they would play in reverse, and if you stopped scrolling, then the animation would stop too. Basically, I needed to move the GIF to a certain frame based on the current scroll progress.

The scrolling part was easy (thanks, ScrollMagic!), but moving to a specific frame turned out to be pretty hard. The only library that I could find that had this feature was libgif-js. It works by taking an existing gif image element, replacing it with an HTML5 canvas, then drawing the image to that canvas instead. Unfortunately, it didn’t work consistently — when the frame changed, portions of the image that should have disappeared stayed visible. Perhaps this was related to the fact that these gifs had a transparent background. Whatever the reason, these artifacts made it look like the images had been passed through Needs More JPEG.

Pictured: not the desired effect.

I wasn’t about to quit, though. When I first visited the libgif-js page, I had noted that it hadn’t seen an update in years — but there were several open pull requests. One of these (with just 3 lines changed!) turned out to be the key to fixing my gifs. Thanks, ProGM!

This PR did just one thing: exposed the “frames” property that libgif-js used behind the scenes. But what, exactly, is a frame? It turned out that the library was storing individual frames as ImageData objects, which would then be drawn to a canvas when necessary. But once you have it drawn to a canvas, you could get that same image data as a data URL by calling canvas.toDataURL. And if you have it as a data URL, you could skip the canvas entirely and just set the original image’s source to be that data URL.

The joys of daisy-chaining!

Once I did that, all my weird artifact problems went away. Success!

Of course, this approach wasn’t very efficient —it would recompute the data URL every time the frame changed. Also, libgif-js didn’t have very good error handling, which made it annoying to track down bugs. So I decided to fork the library and fix a few of these problems myself. I ended up making a few more improvements too, such as:

I also put it up on npm, so it can be easily used with Browserify and Webpack. Check it out on Github, and let me know what you think!

--

--

Ian Sibner

Engineer at Airbnb ☃ Former intern at Palantir/Versal ☃ M&T ’16 ☃ Unicode snowman enthusiast