Two GIFs of the same size on screen can differ in file size by a factor of ten.
The reason is inside the format: palettes, LZW and how frames are stored.
Once you know how those parts work, it's obvious which settings will help your GIF and which won't.
What's inside a GIF file
A GIF is a short sequence of blocks:
- A header saying GIF87a or GIF89a, and the canvas width and height.
- An optional global color table: the palette of up to 256 colors.
- For each frame: a graphic control extension with the delay, transparency and disposal method, then an image descriptor with the frame's position and size, an optional local palette and the compressed pixels.
- An optional application extension that sets the loop count, and optional comments.
You can see all of these for any GIF in the GIF Metadata Viewer.
Step one: the 256-color palette
Every pixel in a GIF frame is stored as a number pointing into a palette of at most 256 colors. A full-color image has to be quantized first: the encoder picks the 256 colors that best represent it and maps each pixel to the nearest one.
This is where most quality is lost, and it's why GIF gradients show bands. Smaller palettes mean shorter numbers per pixel and more repetition, so they compress better.
Dithering: hiding the missing colors
Dithering fakes colors that aren't in the palette by mixing nearby ones in a fine pattern, the way a newspaper prints shades with dots. Floyd-Steinberg dithering spreads each pixel's rounding error to its neighbors; ordered dithering uses a fixed grid pattern.
The eye blends the dots into smooth gradients, but compression sees random noise. In our tests, dithering made a 128-color GIF about twice as large as the same GIF without it.
Step two: LZW compression
GIF compresses the stream of palette numbers with LZW. As it reads pixels left to right, it builds a dictionary of sequences it has already seen and replaces repeats with short codes.
Long runs of identical or repeating pixels become tiny. Noise, dithering and fine texture produce few repeats and compress poorly. That's the single biggest reason flat graphics are small and photos are big.
LZW reads row by row, so horizontal repetition helps most. A horizontal gradient compresses far worse than the same colors arranged in vertical stripes.
Lossy LZW
Standard LZW is lossless. Lossy LZW, popularized by gifsicle and its --lossy option, bends the rule slightly: when the next pixel is almost the color the dictionary expects, it uses the expected color and keeps the run going.
The output is still a perfectly normal GIF, just with tiny color errors that the eye rarely catches. That's why lossy compression often halves a GIF at no visible cost.
Frame optimization
Animated GIFs don't need to store every frame in full. An optimizer compares each frame with the previous one and:
- crops the frame to the rectangle that actually changed;
- marks unchanged pixels transparent so they compress to almost nothing;
- chooses a disposal method telling the viewer whether to keep, clear or restore the previous frame.
A screen recording where only the mouse moves can shrink enormously this way. Busy footage where every pixel changes gains much less.
This is also why editing an optimized GIF is tricky: tools first have to rebuild full frames. Ours do that automatically, which is how Reverse GIF can play optimized GIFs backwards without glitches.
Putting it into practice
- Reduce colors to 128 or 64 for graphics and screen recordings.
- Turn dithering off unless gradients band badly.
- Use lossy compression for anything photographic.
- Make frames smaller with Crop GIF and Resize GIF.
Compress GIF combines all of these. For measured results, see How to Reduce GIF File Size: 9 Methods That Actually Work.
Frequently asked questions
Is GIF compression lossless?
The LZW compression inside GIF is lossless. Quality is lost earlier, when an image with millions of colors is reduced to a 256-color palette. Lossy GIF encoders add a second, optional lossy step on top.
Why are photographic GIFs so large?
Photos and video have gradual color changes and noise, so neighboring pixels rarely repeat exactly. LZW compresses repetition, so it struggles. Flat graphics are the opposite and compress very well.
What does gifsicle's --lossy option do?
It lets the encoder replace pixels with slightly different palette colors when that extends a matching run in its LZW dictionary. Higher values allow bigger differences and give smaller files.