DEV Community

Cover image for APNG vs GIF for Small Web Animations: Transparency, Loops and File Size
Zippic
Zippic

Posted on Originally published at zippic.hashnode.dev

APNG vs GIF for Small Web Animations: Transparency, Loops and File Size

Spinners, success checkmarks, a waving mascot on an empty state, chat stickers: small looping animations still get exported as GIF by default, mostly out of habit. GIF works everywhere, but it was designed in 1987, and its limits show up quickly once the animation has soft edges or sits on a dark background.

APNG (Animated PNG) is the other format that every major browser plays natively without JavaScript. Here is when it beats GIF, when it doesn't, and a few practical details about loops, timing and file size.

TL;DR: use APNG when the animation has soft edges or translucency, set num_plays to 1 for one-shot animations, keep frame delays in multiples of 10 ms, and trim frames before you compress.

What GIF can and can't store

From MDN's image format guide:

  • Each GIF pixel is an 8-bit index into a palette of 24-bit colors, and the palette has at most 256 entries. Anything with gradients or many shades gets dithered.
  • Pixels are opaque unless one palette index is designated as transparent, and pixels with that index are fully transparent. There is no partial transparency.

That second point matters most for UI work. Anti-aliased outlines, soft shadows and translucent highlights all rely on partial alpha. In a GIF, every pixel has to snap to fully opaque or fully transparent, which is where jagged edges and the familiar light halo around stickers come from. The halo usually appears when the artwork was flattened against a white background before export and then placed on a dark one.

What APNG adds

APNG extends PNG, so each frame can use any PNG color mode, including true color with an 8- or 16-bit alpha channel. Compression is lossless. MDN describes APNG as a good fit for "basic animations that do not need to synchronize to other activities or to a sound track, such as progress indicators, activity throbbers, and other animated sequences".

The comparison below is a demonstration from a single 320×270 frame with an anti-aliased outline and a soft, semi-transparent drop shadow. For the GIF, semi-transparent pixels were flattened onto a white matte and then cut with a 1-bit transparency threshold, which is how a typical GIF export behaves. The other side is the original PNG. Both sit on a #1f2937 background, and the boxed area on the lower-left outline is enlarged 3x. The GIF shows a light, jagged fringe along the outline, and the shadow is gone. The PNG keeps smooth edges and the shadow.

One frame exported as GIF on a white matte and as the original PNG, on a dark background and zoomed 3x. The GIF has a light jagged fringe on the outline and no shadow; the PNG keeps smooth edges and the soft shadow

Browser support

MDN lists APNG support from Chrome 59, Edge 12, Firefox 3, Opera 46 and Safari 8. The MIME type is image/apng, and the file can keep the .png extension. You use it like any other image:

<img src="/img/loader.png" width="48" height="48" alt="Loading">
Enter fullscreen mode Exit fullscreen mode

Where GIF still makes sense

If a file has to pass through a system you don't control that only accepts .gif, such as an upload field or a third-party integration, GIF is the safe choice. And if you are optimizing purely for bytes on a photographic or detailed animation, MDN points out that animated WebP and AVIF compress better than both. APNG sits in the middle: lossless, full alpha, and universally supported in current browsers.

Loops and timing: two details worth knowing

Loop count. APNG stores a num_plays value. According to the W3C PNG specification, 0 means play indefinitely, and any other number means the animation stops on its final frame after the last play. That makes a one-shot micro-animation easy: set loops to 1 and make the last frame the resting state. A success checkmark plays once and stays checked, with no JavaScript needed to swap in a static image. Loaders want 0.

Frame delay. Each frame's delay is stored as a fraction of a second (delay_num / delay_den). Many encoders write it in hundredths of a second, so a 33 ms delay may end up as 30 ms. Picking multiples of 10 ms (50, 80, 100) keeps the timing you set identical to what ends up in the file.

If you also respect prefers-reduced-motion, you can swap in a static image with <picture>:

<picture>
  <source srcset="/img/mascot-still.png" media="(prefers-reduced-motion: reduce)">
  <img src="/img/mascot.png" alt="Mascot waving">
</picture>
Enter fullscreen mode Exit fullscreen mode

Building an APNG from PNG frames

Export each frame as a transparent PNG at the final size, then assemble them. Command-line tools like APNG Assembler work well in a build pipeline. For a one-off, a browser tool is quicker. zippic's APNG Maker is one option. It processes images locally in the browser without uploading them, and lets you set the canvas size, a default delay, per-frame delays, the loop count and a fill color.

A few defaults to change:

  • Canvas defaults to 640×480. Set it to your frame size. Frames are scaled to fit and centered, so frames that don't match the canvas get padded with the fill color.
  • Fill Color defaults to #00000000 (fully transparent). Leave it that way if you want alpha.
  • Default Frame Delay defaults to 30 ms, which is fast for most UI motion. Start around 80–100 ms and adjust individual frames in the frame list.
  • Loop Count defaults to 0 (infinite). Change it to 1 for one-shot animations.

APNG Maker with 10 frames loaded: canvas 320×270, 100 ms per frame, loop count 3, transparent fill

Keeping the file small

Full color plus alpha can get heavy, so cut at the source first:

  1. Trim the canvas. Empty transparent margins still cost bytes in every frame.
  2. Drop frames. A 10-frame loader at 100 ms can read just as well as 20 frames at 50 ms, at roughly half the frame data.
  3. Hold instead of repeating. For a pause, use one frame with a longer delay rather than several identical frames.
  4. Then compress. zippic's homepage compressor has an APNG output format with a quality slider. In the test shown below, the 10-frame example went from 15.33 KB to 5.52 KB at 75% quality. Results depend heavily on the artwork, so preview the output to check that the animation and edges still look right.

zippic homepage compressor with APNG output selected: 15.33 KB to 5.52 KB at 75% quality

A real-world constraint: LINE stickers

For a platform that requires APNG, look at LINE. Its Creators Market accepts animated stickers only as APNG, with a published spec: 5–20 frames per sticker, 1–4 loops, at most 4 seconds of total playback across all loops, a maximum of 320×270 px with at least one side of 270 px or more, a transparent background, and up to 1 MB per file. A GIF won't upload, and an APNG left at the default infinite loop gets rejected too. It's a useful checklist even if you never ship a sticker, because it's a sensible budget for any small looping UI animation.

Quick decision guide

  • Soft edges, translucency, or a dark or variable background: APNG
  • Must pass through a GIF-only pipeline: GIF
  • Bytes matter most and you can provide fallbacks: consider animated WebP or AVIF
  • One-shot animation that should come to rest: APNG with loop count 1

Sources

Top comments (0)