What a GIF actually is
A GIF (Graphics Interchange Format) packs many frames into one image file that the browser plays automatically and loops forever. It's just an image — so you embed it with a plain <img> tag.
It's an image
Use <img> like any photo — no <video>, no player.
Auto-plays & loops
Starts on load and repeats — you can't pause or scrub it.
Always silent
GIFs carry no audio track at all.
Big & low-color
Limited to 256 colors and large file sizes — the catch.
.gif — they show the “short silent loop” idea without shipping a heavy file.Add a GIF to the page
Exactly like an image: set src, write meaningful alt, and include width/height so the layout doesn't jump while it loads.
Stand-ins for looping GIFs (a bouncing dot and a spinner).
HTML
<img src="loading.gif"
alt="Loading animation"
width="130" height="130">
CSS
img { border-radius: 12px; max-width: 100%; height: auto; }
/* A GIF can't be paused or styled internally —
it just plays. To control playback, use a video instead. */
JavaScript — fake pause/play by swapping a still frame
// A real GIF can't be paused. The classic workaround is to swap
// the .gif file for a still .png (a single paused frame) on click.
// <img class="gif-toggle"
// src="loading.gif"
// data-still="loading-still.png"
// alt="Loading animation">
document.querySelectorAll('.gif-toggle').forEach(img => {
const animated = img.src;
const still = img.dataset.still;
let playing = true;
img.style.cursor = 'pointer';
img.title = 'Click to pause/play';
img.addEventListener('click', () => {
playing = !playing;
img.src = playing ? animated : still;
});
});
When to use a GIF — and when not to
GIFs are fine for tiny, simple loops (a small icon, a reaction). For anything longer or detailed, a muted looping video is much smaller and sharper.
| Animated GIF | Muted loop video (mp4/webm) | |
|---|---|---|
| File size | Large (often MBs) | 5–10× smaller |
| Colors / quality | Max 256 colors | Full color, crisp |
| Audio | Never | Optional (muted here) |
| Controls | None (always loops) | Can pause / control |
| Best for | Tiny icons, stickers | Everything longer |
A “GIF” that's really a video
To get GIF-like behavior (auto-play, loop, no controls) at a fraction of the size, use a <video> that's muted, loop, autoplay, and playsinline.
HTML
<video autoplay loop muted playsinline width="320"> <source src="clip.webm" type="video/webm"> <source src="clip.mp4" type="video/mp4"> </video>
CSS
video { width: 100%; height: auto; border-radius: 12px; }
mutedis required for autoplay to work in most browsers.playsinlinestops iOS from forcing fullscreen.- Offer
.webmfirst (smaller),.mp4as a fallback.
Create a GIF (and shrink it)
If you do need a real GIF, make it small from the start.
Create
Tools like EZGIF, Giphy, or Photoshop (Export › Save for Web) turn a clip into a GIF.
Shrink dimensions
Keep it small on screen — a 320px-wide GIF is a fraction of a 1080px one.
Fewer colors & frames
Reduce the color count and trim frames/length — the two biggest size wins.
Or convert to video
EZGIF and Cloudinary can turn a GIF straight into .mp4/.webm.
Respect motion preferences
Auto-playing, never-ending motion can be distracting — or harmful for people with vestibular conditions. A real GIF can't be paused, which is another reason to prefer video. When you control the animation (video or CSS), honor the user's reduce motion setting.
CSS
@media (prefers-reduced-motion: reduce) {
video { /* pause or swap for a still image */ }
.animated { animation: none; }
}
- Write real
alttext describing what the animation shows. - Keep loops short and avoid rapid flashing (a seizure risk).
- Prefer
<video>so users can pause; offer a still poster as a fallback.
The whole thing as one file
Everything above — the looping GIF-style stand-ins, the muted-loop video alternative, and the reduced-motion rules — combined into one complete HTML file. Copy it into a new file, open it in a browser, and it just works — no libraries, no build step. Here's the live result, then the full code.
Live preview
Complete HTML — copy this whole file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Animated GIF Loops</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #1f2433; background: #f6f7fb; line-height: 1.6; }
.wrap { max-width: 760px; margin: 0 auto; padding: 36px 24px 60px; }
h1 { font-size: 2rem; margin-bottom: 8px; }
h1 .accent { color: #38bdf8; }
.lead { color: #5b6473; margin-bottom: 28px; }
h2 { font-size: 1.2rem; margin: 32px 0 12px; }
p.note { color: #6b7280; font-size: .9rem; margin-top: 10px; }
/* ===== GIF-style looping stand-ins (CSS, no heavy .gif file) ===== */
.gif-stage { display: flex; gap: 18px; flex-wrap: wrap; }
.gif-box { width: 130px; height: 130px; border-radius: 12px; background: linear-gradient(135deg,#38bdf8,#9b7bff); display: grid; place-items: center; overflow: hidden; }
.gif-box .ball { width: 28px; height: 28px; border-radius: 50%; background: #fff; animation: bounce 1.1s ease-in-out infinite; }
@keyframes bounce { 0%,100% { transform: translateY(-30px); } 50% { transform: translateY(30px); } }
.gif-box .ring { width: 56px; height: 56px; border: 6px solid rgba(255,255,255,.35); border-top-color: #fff; border-radius: 50%; animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* ===== The video alternative: GIF-like behavior, far smaller ===== */
video { width: 320px; max-width: 100%; height: auto; border-radius: 12px; display: block; background: #111; }
/* A real GIF embeds exactly like a photo */
img.gif { border-radius: 12px; max-width: 100%; height: auto; }
/* ===== Respect motion preferences ===== */
@media (prefers-reduced-motion: reduce) {
.gif-box .ball, .gif-box .ring { animation: none; }
}
</style>
</head>
<body>
<main class="wrap">
<h1>Animated <span class="accent">GIF</span> Loops</h1>
<p class="lead">A GIF is just an image that moves — a short, silent, looping animation embedded with a plain <code><img></code> tag.</p>
<h2>1. Looping GIF stand-ins</h2>
<div class="gif-stage">
<div class="gif-box"><div class="ball"></div></div>
<div class="gif-box"><div class="ring"></div></div>
</div>
<p class="note">CSS stand-ins for looping GIFs (a bouncing dot and a spinner) — the “short silent loop” idea without a heavy file.</p>
<h2>2. Embed a real GIF</h2>
<img class="gif" src="loading.gif" alt="Loading animation" width="130" height="130">
<p class="note">Set <code>src</code>, write meaningful <code>alt</code>, and include <code>width</code>/<code>height</code> so the layout doesn't jump.</p>
<h2>3. The video alternative</h2>
<video autoplay loop muted playsinline poster="">
<source src="clip.webm" type="video/webm">
<source src="clip.mp4" type="video/mp4">
Your browser can't play this clip.
</video>
<p class="note">A <code><video></code> that's <code>muted loop autoplay playsinline</code> behaves like a GIF at a fraction of the size — and users can pause it.</p>
</main>
</body>
</html>
Keep building
See Images, Video, Video & Multimedia, and other Media Patterns — or browse the full Component Library.