Update 2024
This question was posted in 2010 and is in need of an update. The previous answers use techniques and libraries that are rarely used anymore. Yet, it continues to be cited as a solution.
screenshot
Browsers now support the video element. These will not play animated GIF images directly. Yet, it's very easy to convert GIF images to MP4 format using graphics applications or one of the many online converters. The WEBM format is a widely supported alternative when a transparent background is required.
Video has many advantages over an animated GIF. A few of these are:
- Greatly reduced file size
- No libraries are required
- Plays while loading
- Ability to use media sources
- Visually the same as the GIF
- And more...
Code Snippet
The snippet plays an MP4, WEBM, and GIF side by side. The MP4 and WEBM use an HTML-5 video element. The GIF uses the library from the most upvoted answer. There are buttons for play, pause, and seek.
const toggle = document.querySelector('input[type=checkbox]');
const mp4 = document.querySelector('#mp4 video');
const webm = document.querySelector('#webm video');
const gif = new SuperGif({
gif: document.querySelector('#gif img'),
loop_mode: true,
auto_play: true,
max_width: 150,
// on_end:.
// loop_delay:
show_progress_bar: false
});
gif.load();
play.addEventListener('click', () => {
mp4.play();
webm.play();
gif.play();
})
pause.addEventListener('click', () => {
mp4.pause();
webm.pause();
gif.pause();
})
seek.addEventListener('change', () => {
let percent = seek.value / 100;
let frame = Math.floor(gif.get_length() * percent)
gif.move_to(frame);
let position = Math.floor(mp4.duration * percent);
mp4.currentTime = position;
position = Math.floor(webm.duration * percent);
webm.currentTime = position;
})
mp4.addEventListener('timeupdate', () => {
seek.value = Math.floor(100 * mp4.currentTime / mp4.duration);
});
body {
font-family: sans-serif;
.container {
margin-top: 1rem;
display: flex;
background-image: linear-gradient(to bottom right, red, yellow);
}
input[type=button] {
min-width: 4rem;
}
input[type=range] {
min-width: 20rem;
}
figure {
border: thin solid white;
border-radius: 0.5rem;
display: inline-block;
padding: 0.25rem;
margin: 0.5rem;
background-color: transparent;
}
figcaption {
color: white;
text-align: center;
}
video,
img {
width: 150px;
height: auto;
}
<input type="button" id="play" value="Play">
<input type="button" id="pause" value="Pause">
<input type="range" id="seek" min="0" max="100" value="0">
<div class="container">
<figure id="mp4">
<figcaption>
205kb Video MP4
</figcaption>
<video autoplay muted loop>
<source src="https://i.yourimageshare.com/i0rmDubApf.mp4">
</video>
</figure>
<figure id="webm">
<figcaption>
222kb Video WEBM
</figcaption>
<video autoplay muted loop>
<source src="https://i.yourimageshare.com/S1S9fJww3M.webm">
</video>
</figure>
<figure id="gif">
<figcaption>
746kb Animated GIF
</figcaption>
<image src="https://i.postimg.cc/t4zZRyZH/rubik.gif" />
</figure>
</div>
<script src="https://cdn.jsdelivr.net/gh/buzzfeed/libgif-js/libgif.js"></script>