GIFs used to be just atmospheric decoration. Now they’re usually short, looping, silent videos. As videos, it’s not very nice to have them play automatically. It’s much better when they have a play button and only start playing when that’s clicked or tapped.
So I recently went down a rabbit hole of ways to make gifs pause by default and only play when interacted with. This post is intended to document some of the things I found.
So, what did I find?
How to Pause a GIF
Strictly speaking, you can’t.
Let me explain what I mean by this. As far as I can tell, there’s no programmatic way to pause a GIF and have it still be the same GIF file in an ‘img’ tag in the browser. You can hide it and replace it with a static image. Or you can replace it with some other kind of animating element (such as a canvas, or CSS animation). But there are libraries or code snippets available for doing these things. Here are a few of them.
1. The Thing That Works Right But is Not a GIF
One of the first things I stumbled across was this CodePen. This works right from a user point of view, in that it allows you to pause the animation, and resume from where you left off, whereas most of the other methods let you stop it, but only restart animating from the beginning. However, as the section heading says, it’s not an animated GIF. The image (a PNG file) contains a series of frames side by side, and the CodePen uses CSS animations to switch from frame to frame. You can pause the animation by setting the animation-play-state property to ‘paused’, but, alas, this property doesn’t work on GIFs.
2. The One With The Simplest Code
CSS PLAY has a demo that accomplishes play/stop in a small amount of code (about 8 lines of CSS, which would probably be about 20 with more line breaks for readability), and doesn’t do DOM manipulation, relying on the :active and :hover pseudo-classes to show or hide the animated GIF by setting the visibility to hidden or visible. An element (in this case an ‘a’ tag) that encloses the ‘img’ tag has its background image set to the static image that’s displayed while the GIF isn’t animating.
One downside is that this method requires providing a separate static image for the stopped state (the next two methods are libraries that generate the static image for you by programmatically taking a screen shot of the gif).
The code for CSS PLAY’s implementation of this concept is copyrighted and not released under an open source license. The code requires a donation for use and special permission for commercial use. See the Copyright section of its demo page for details.
3. Gifffer
Gifffer (three f’s) is a JavaScript library with a small minified footprint. It requires using a custom attribute instead of ‘src’ on the ‘img’ tags and then calling the Gifffer() function in your window.onload(). It works by DOM manipulation, programmatically replacing the ‘img’ element with a div inside a button, and then putting the img back when you want it to animate.
I assume that you would have to call Gifffer() again if you add additional GIFs to the page after it’s loaded.
4. Freezeframe.js
Freezeframe.js works similarly to Gifffer but is more full featured. It appears to have a fade effect when transitioning between the animating and stopped states, which looks nice. It doesn’t require jQuery but is available as a jQuery plugin.
The DOM manipulation for Freezeframe.js and Gifffer might conflict with the DOM manipulation done by React or similar frameworks.
5. react-gif-player
Speaking of React, react-gif-player is a GIF player for React. It encloses the img element within divs and changes the img’s src attribute when clicked. You do have to provide a separate still image file for it to switch to when paused.
I didn’t find any GIF player libraries for Angular or Vue.
6. gif-player
One that does allow pausing at a specific frame is gif-player (no relation to react-gif-player). It uses the WebComponent API to provide a custom ‘gif-player’ element, which means it should be compatible with React or other modern frameworks. The user experience isn’t as simple as clicking on a play button though. It starts in a default state (you can either set it to autoplay or be paused by default), and then pauses when you mouse over it or touch it, and fast forwards/rewinds by moving the mouse/finger left and right across the image.
It achieves this by processing the GIF using the omggif.js library in the browser and then rendering each frame to a ‘canvas’ element. While this does replace the img tag, it demonstrates that it’s possible to have a pausable client-side GIF player without any server-side shennanigans.
7. A note on the <video> tag
HTML5 has a ‘video’ tag that allows playback and pausing. However, GIFs (which would be a media type of “image/gif” in the ‘source’ tag) aren’t supported. A tutorial on HTML5 video says to convert them from GIF to a video format using ffmpeg, which can be run from the command line. This might be a good approach if you can pre-process all your GIFs or run a background process on the server.
Which one wins?
From trying the demos of these libraries, Freezeframe.js seemed to be the best experience from the user’s point of view. This will probably be your best bet unless you’re using React, in which case react-gif-player was pretty smooth.
This post was adapted from this twitter thread. If you liked this, consider following me over there. Have you made GIFs pausable for the user? What approach worked for you?