Lottie vs GIF vs Video: Which to Use on Your Website
A technical comparison of Lottie, GIF, and MP4/WebM for web animation — how each format works, when each one wins, and how to measure the difference yourself.

Three formats, one animated element on a page, and a decision usually made by habit rather than analysis. The useful way to choose is to understand what each format is at the byte level, because that determines everything downstream — size, sharpness, colour fidelity, CPU cost, and whether your code can talk to the animation at all.
What each format actually is
GIF is a raster format from 1987. It stores a sequence of bitmap frames, each limited to at most 256 colours, compressed with LZW. No inter-frame motion compensation, no modern entropy coding — the root cause of nearly every problem with it.
MP4 and WebM are containers holding video compressed by a modern codec: H.264 or AV1 in MP4, VP9 or AV1 in WebM. Also raster, but they encode the difference between frames, use motion vectors to describe how blocks of pixels move, and decode on dedicated hardware in nearly every device shipped in the last decade.
Lottie is not an image format at all. It is a JSON description of a vector animation — shape layers, paths, transforms, keyframes, easing curves — exported from After Effects and rendered at runtime by a player in the browser. Nothing is pre-rasterised; the browser draws the shapes fresh every frame at whatever size and pixel density the display has.
That is the whole comparison in miniature: Lottie trades storage for computation, GIF and video trade computation for storage.
Sharpness and colour
Because Lottie renders vectors at runtime, it is resolution-independent. The same file is crisp on a 1× laptop, a 3× phone, and a 4K monitor, at any CSS size. There is no "export at 2×" step, because there is no export size.
GIF and video are fixed-resolution rasters. Ship a 400px-wide asset at 400 CSS pixels on a 3× device and the browser upscales it — visibly. The fix is to export at 2× or 3× and scale down, which multiplies file size by the square of the factor.
Colour is where GIF fails hardest. A 256-colour palette cannot represent a gradient, a soft shadow, or a subtle brand colour ramp without dithering — the speckled noise you see across large flat areas in GIFs. Worse, GIF transparency is binary: a pixel is fully opaque or fully transparent. With no partial alpha, every anti-aliased edge is matted against one assumed background colour, so that GIF on a differently-coloured section shows a visible fringe or a jagged edge.
Lottie has full alpha and unrestricted colour. Video codecs have full colour but no usable alpha in practice — support exists, patchily, which is why so many teams end up with a video carrying a hard-coded white background.
File size, and why the usual comparison is misleading
These formats scale along different axes:
- A GIF grows with pixel dimensions, frame count, and complexity. Duration is expensive because every frame is stored.
- A video grows with dimensions and duration too, but far more slowly, because inter-frame compression makes a mostly-static scene almost free to continue.
- A Lottie grows with layer count, path points, and keyframes. Duration is nearly free — a five-second loop and a twenty-second loop of the same complexity weigh about the same — but visual complexity is expensive.
So "Lottie is smaller than GIF" is usually true for the things Lottie is for (icons, loaders, flat illustration) and badly false for things it is not (a traced photograph with thousands of path points, or a base64 PNG embedded inside the JSON).
Beware any comparison table quoting fixed file sizes for "the same animation" across formats. There is no such thing as the same animation across these formats — the numbers depend entirely on the content. Export your own asset in all three and weigh the files.
How to measure it yourself
Export your animation as an optimised Lottie, and as a GIF, MP4, and WebM at display dimensions. Compare on-disk sizes, then load each in a page and read the transferred size in the DevTools Network panel: text-based JSON compresses substantially over the wire with Brotli or gzip while already-compressed GIF and video barely compress at all, so an on-disk comparison overstates Lottie's cost. Then count the player — a JavaScript dependency with its own transfer cost, and if one animation is the only thing using it, that bundle belongs in the comparison.
When video is genuinely the right answer
Lottie advocacy skips this. Use an MP4 or WebM when any of these is true.
- The content is photographic or filmed. Vectors cannot describe a photograph. Real footage or a screen recording of a real interface is video, full stop.
- It uses heavy blur, film grain, particle simulation, or gradient meshes. Most of these either do not survive the Lottie export, or survive only by being rasterised into the JSON.
- It runs longer than a few seconds. Lottie's per-frame rendering cost is paid continuously for as long as it plays. A ninety-second piece is a video.
- It needs playback controls, buffering, or streaming. That is what
<video>is for.
For a background loop, WebM with VP9 is usually the right pick — muted,
playsinline, with a poster frame so nothing pops in. The
delivery specifications on the process page list the
formats we ship as standard, and our
video editing and post-production service
covers encoding. A product explainer built on real screen recordings sits
firmly in this category — see
why SaaS companies need explainer videos
for how that asset differs from a UI micro-interaction.
When Lottie wins on capability, not just weight
The argument for Lottie that has nothing to do with file size: it is a live
object your code can control. Named markers let you play frames 0–30 on
hover and 30–60 on click. Bind goToAndStop to scroll position and it
becomes a scroll-driven graphic. Being vector data, it can be recoloured at
runtime for a dark mode with no re-export. A loader that turns into a
success tick when a promise resolves is one animation with two segments,
rather than two video files and a swap.
None of that works with a GIF or an MP4 without a separate asset per state.
dotLottie
The .lottie format is a zipped container holding the animation JSON plus
any images, fonts, and even multiple animations in one compressed archive.
The compression usually makes it meaningfully smaller than the raw JSON, and
because assets travel inside the bundle, you cannot ship a JSON referencing
image files that never reached the server.
Use it when your player supports it — the dotLottie web component and React
player do natively. Keep plain JSON on an older lottie-web setup, on a
platform whose Lottie element expects a JSON URL, or in a pipeline that
inlines the animation. We deliver both, which is why our
Lottie and web motion service lists two
output formats rather than one.
SVG renderer versus canvas renderer
This choice decides whether a Lottie feels smooth or janky, and it is an architectural difference, not a setting.
The SVG renderer creates real DOM nodes for every shape and mutates their attributes each frame, so the browser runs style, layout, and paint across all of them. You get crisp scaling and CSS access to the animation's internals — but cost grows with node count, and a busy illustration can mean hundreds of elements recalculated sixty times a second.
The canvas renderer draws to a single <canvas> element. Node count
stops mattering, so complex artwork gets dramatically cheaper — at the cost
of rasterising at the size it is drawn (you handle device pixel ratio
yourself) and losing CSS access to the interior.
Our rule of thumb: SVG for small, simple UI animations and anything that must scale arbitrarily; canvas for busy illustrations, many simultaneous instances, or anything that must hold up on low-end mobile.
How to measure that yourself
Do not take a rule of thumb into production. In Chrome DevTools, open the Performance panel, enable CPU throttling at 4× or 6×, and record while the animation plays. Look at how much of each frame goes to Rendering and Painting, and whether frames blow past your refresh-rate budget. Swap the renderer, record again under identical throttling, and compare. That means something because it is your artwork on your page; someone else's benchmark is not. The same recording tells you whether Lottie or video is cheaper here — video decode largely runs on dedicated hardware and profiles very differently from main-thread vector rendering.
Accessibility applies to all three
A CSS prefers-reduced-motion media query does nothing to a
JavaScript-driven Lottie player, and nothing to an autoplaying <video>.
Handle it in code:
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (reduce) {
renderStaticPoster();
} else {
player.play();
}Beyond that: ship a static poster from the resting frame, so reduced-motion,
no-JS, and failed-fetch states show the intended composition rather than an
empty box. Mark decorative animation aria-hidden rather than inventing alt
text for a spinner. Never autoplay sound, and avoid rapid flashing.
The short version
Lottie for anything vector — icons, loaders, empty states, toggles, flat illustrated heroes — and especially where you want runtime control. MP4 or WebM for anything photographic, filmed, screen-recorded, heavily blurred, or longer than a few seconds. GIF essentially never on a production site.
If you are carrying a heavy hero GIF or an autoplaying MP4 that still looks soft, our guide to shipping Lottie without the performance tax covers the loading strategy side of the swap.
RELATED READING
Web AnimationLottie Animations Without the Performance Tax: A Practical Guide
How to use Lottie animations on marketing and product pages without hurting Core Web Vitals — file size, rendering, and loading strategy.
Web AnimationWebsite Animation That Converts, and the Kind That Hurts
Where website animation helps visitors understand and act, where it quietly costs you, and how to brief Lottie and web motion that ships light and accessible.