# 一个 GIF 里到底装着什么

GIF 是一摞长方形，每个都带着一只计时器和一张调色板，而人们对这个格式的抱怨，几乎都出自这三样里的某一样。下面讲每个部分各做什么，以及怎么弄清楚你的文件把体积花在了哪一样上。

[打开GIF 分析](https://abox.tools/zh/gif-analyzer/): 帧、延时、调色板，以及每个字节的去向。

最后更新 2026年8月26日

## 简短的回答

一个 GIF 是一块画布、一串往上画的长方形，外加一张调色板，说明那些长方形里的数字各代表什么颜色。每个长方形带着三样东西：它该停留多久、之后该拿它怎么办，以及可有可无的一张自己的调色板。

人们觉得这个格式奇怪的地方，几乎都出自那串长方形。你的 GIF 大得离谱，要么是那些长方形每次都是整块画布，要么是里面塞了三百张调色板。它播得太慢，是因为延时低到了任何浏览器都不肯往下走的那条地板以下。它拖出尾巴，那是那个叫*处置*的字段。

想知道某个具体文件属于哪一种，打开 [GIF 分析](https://abox.tools/zh/gif-analyzer/)把它拖进去。这一页剩下的部分，讲的是那些数字都是什么意思。

![一个 GIF 的摘要卡片：版本、画布尺寸、文件大小、帧数、循环次数和用了多少种颜色。](https://abox.tools/screens/whats-inside-a-gif/facts.webp)

播放器从不告诉你的一切，全从一个文件里读出来。

## 帧是长方形，不是画

只见过 GIF 播出来的人，在这儿最容易吃惊。一帧并不是那一刻动画的画面。它是一个长方形，有自己的位置和自己的大小，画在前面几帧留下的东西之上。

那个长方形可以是整块画布，而在做得糟的文件里它每次都是。但 GIF 是允许只存下自上一帧起变过的那部分的——而在画面大半不动的地方，这就是一个 12 MB 的文件和一个 900 KB 的文件之间的差别。一段几乎静止的窗口录屏能做得很小，而同一段录屏从一个马虎的转换器里出来就不小，原因也在这儿。

光看动画，你分不出自己手上是哪一种，两者看起来一模一样。唯一的办法是看每一帧存了什么，而分析器专为此备了一个视图：把它切到*每帧实际存的东西*，你要么看到透明底上一排小形状，说明编码器干了它的活；要么一遍又一遍看到整张画面，说明它没干。

这个格式里任何地方都没有运动补偿。不会有东西被存成「和上次一样，只是往左挪了四个像素」，视频编码器才那么干。变化区域这个招数是 GIF 仅有的一点省法，而它非常值钱。

## 延时，以及每个浏览器都强推的那条地板

每一帧都存着自己要停多久，单位是百分之一秒。这个格式只有这一种单位，所以一个文件能要的最快是 0.01 秒——每秒一百帧——最长约 655 秒。

它不会得到每秒一百帧。**每个浏览器都把低于 0.02 秒的延时抬到 0.10。**这条规矩 1996 年写进了 Netscape Navigator，为的是那个年代旋转的地球仪和会动的「施工中」牌子，之后每个浏览器都照抄了下来。从来没人删掉它，也不会有人删。

所以一个每帧都写着 0.01 秒的 GIF，播出来是每秒十帧，不是一百帧。它比造它的那个程序打算的慢十倍，而文件对此毫无提示：里面的延时正是当初要求的值。这是这个格式里最常见的意外，也是分析器要报两个时长的原因——文件说的那个，和浏览器真正会照办的那个。

无论文件是在哪儿造的，解法都是写 0.02 而不是 0.01。那是每秒 50 帧，也是真正的上限，比任何用途需要的都快。实际上 0.05 秒——每秒二十帧——差不多就是值得去要的最快了。

延时还能告诉你另一件事。要是它们全都一样，这个文件是由一组固定帧率的帧做出来的。要是它们参差不齐——这儿 0.04，那儿 0.11——那是某个东西转了一段视频、丢掉了一些帧，再把邻居拉长去补上窟窿。而要是最后一帧比其余的长得多，那是有意为之：让动画在循环回去之前停一下，就是这么做的。

## 处置：决定它会不会拖尾巴的字段

每一帧都写明自己的时间到了之后，屏幕上该留下什么。可能的答案有四个，值得知道，因为动画看起来不对的四种方式里，有三种就是这个字段填错了。

- **留在原地。**下一帧直接盖上去。当各帧不透明且彼此完全遮住时，这是对的，而且最省，因为什么都不用清。
- **清回背景。**这一帧的长方形在下一帧落下前被擦掉。透明就需要这个：没有它，下一帧透出来的地方会露出前一帧，一组各自独立的画面就变成了一摞叠影。
- **还原下面原有的东西。**这一帧画上去之前画布上的样子被放回来。一个小东西在静止背景上移动，就是这么存的——每一帧画那个东西，然后背景回来，而写进文件的自始至终只有那个东西的长方形。
- **未指定。**文件没说。所有看图程序都当成「留在原地」，通常没错，偶尔就是透明 GIF 拖出尾巴的原因。

有一处规范和现实分了家。「清回背景」指的是文件头里写着的那个背景色，而每个浏览器都无视它，改成清成透明。这样已经二十五年了。一个指望那个背景色会出现的文件，在做它的人、用做它的那个软件看来是对的，在别处一律是错的。

## 调色板，以及它们要的 768 字节

GIF 的一个像素不是颜色。它是一个数字，指向一张最多 256 色的表，每种颜色占三个字节。所以一张满的表是 768 字节，而一个文件可以让所有帧共用一张，也可以一帧一张，或者两者都有。

两种安排都合法，只是换来的东西不同：

- **共用一张表**，整个文件只花 768 字节，而且颜色在帧与帧之间是稳的。GIF 的闪烁——从视频做出来的文件上那种讨厌的抖动——很多时候不过是调色板在一帧一帧地跳。
- **每帧一张表**，让每一帧都能用上共用表里没有的颜色，画面整个换掉的时候这很要紧。代价是每次 768 字节。一段 300 帧的动画，那就是在存下第一个像素之前，先花掉 230 KB 的调色板。

还有一笔更安静的开销。调色板的长度必须是 2 的幂，所以用九种颜色的帧照样拿到十六格的表，用 130 种的照样拿到 256 格。一定程度的往上凑是躲不掉的。但要是一个文件的表里声明了五千种它的像素从没引用过的颜色，那就是另一回事了：那是为另一张画配的调色板，而最终进到帧里的并不是那张画。分析器会把没用上的格子标出来，让这个形状一眼可见。

## 字节实际去了哪里

GIF 的每个字节都落在为数不多的几个地方，在断定一个文件太大之前，值得知道这几个地方是什么。

- **压缩过的像素。**健康的文件里，几乎全是它。画面本身，过了一遍 LZW——1984 年的一种压缩方案，当初是为电子表格的截图设计的，所以它在大片纯色上表现好，在照片上表现差。
- **调色板。**如上，一张满表 768 字节。
- **每帧的头。**每一帧八个字节的时间信息加十一个字节的描述符。正常文件里不算什么；两千个极小帧的动画里，是 38 KB。
- **分块的外壳。**压缩数据被切成最多 255 字节一段，每段前面放一个长度字节。大约每 256 个字节里有一个，躲不掉，值得看一眼，因为除此之外它完全看不见。
- **元数据。**注释、色彩配置文件和 XMP 包。真正荒唐的结果就出在这一项：一个图像编辑器可能留下 40 KB 的 XML，描述的是几年前做过的一次修改，而在一个小 GIF 上那就是文件的大半。没有任何看图程序会把它画出来。

要看这张表而不是猜，是因为答案因文件而异，而解法直接从答案里长出来。一个 95 % 都是压缩像素的文件，就是画面本身多，只有减帧、缩小尺寸或者减颜色才有用。一个 30 % 是调色板、或者 40 % 是 XMP 的文件，问题便宜得多。

![一条按字节去向拆解 GIF 的条形图，每一帧一行，给出各自的大小和在文件中的占比。](https://abox.tools/screens/whats-inside-a-gif/budget.webp)

字节到底去了哪里，一帧一帧地看。太大的 GIF 几乎总是因为一个看了这张图就明白的原因才大的。

## 循环并不属于这个格式

GIF 规范里没有任何字段说动画会重复。循环来自 Netscape 在 1995 年发明的一个块——一个里面写着 `NETSCAPE2.0` 的「应用扩展」——所有人还是都实现了它，如今互联网上每一个动图 GIF 里都有它。

这也意味着，没有这个块的文件在每个浏览器里都是恰好播一遍就停，在做它的人看来像是坏了。要是一段动画只走一遍，就是这个块不见了；这是最值得先查的几件事之一，而且在任何看图程序里都看不见。

这个块也能写一个次数——播五遍然后停。零表示永远，而几乎所有文件写的都是零。

## GIF 还能捎带的别的东西

有三种块不装画面，而且所有看图程序都跳过：

- **注释。**自由文本，通常是写这个文件的软件的名字，偶尔是作者本来不会选择公开的东西。没有东西会显示它，而这个文件的每一份拷贝都带着它。
- **XMP。**Adobe 的 XML 元数据：什么改过这个文件、什么时候改的，有时还有谁改的。它末尾拖着 258 字节的魔法尾巴，那是为了让块长度算得过去的把戏，也是为什么老老实实去读会读出满屏二进制。
- **纯文本。**1989 年规范里的一个块，要求看图程序按格子在画面上写字。从来没有任何东西实现过它。文件里要是有一个，它写的内容不会出现。

这三样在把文件发出去之前都值得知道：它们是一个 GIF 里可能透露你的部分，而且除非有东西专门把它们剥掉，否则每一次拷贝、每一次重新上传，它们都活着。

## 读一个损坏的文件

GIF 会被截断——中途停掉的下载、从快坏的硬盘上救回来的文件、某个程序只写了一半的东西。因为这个格式是一串块，而不是一整个带索引的结构，被截断的 GIF 通常仍然能读到它断掉的那一点为止：断口之前的每一帧都是完整无损的。

这值得知道，因为大多数软件会干脆拒收这个文件。一个尽量往下读、并且告诉你在哪儿停住的分析器，至少能让你知道有多少活了下来，以及丢掉的是一帧还是最后两百帧。

反过来的毛病也存在：坐在文件结束标记*之后*的那些字节。每个解码器都在那个标记处停下，所以它们从不会被读到、也不会被画出来，而它们通常是某次出错时被接在第一个文件后面的第二个文件。它们是纯粹的重量，切掉不损失任何东西。

## 这些都不需要上传

读一个 GIF 的结构不是什么费劲的活——走一遍块的清单，再加一个小小的解压器——而且从来没有任何技术上的理由，非要把文件送到服务器上去做它。这里的 [GIF 分析](https://abox.tools/zh/gif-analyzer/)把整件事都放在页面里做完：走块、LZW、画到屏幕上的帧，还有那份字节账。

这件事在这儿比在多数活儿上更要紧，因为人们最想拆开看的文件，往往正是他们最拿不准要不要拿出去的那些——救回来的东西、别人发来的东西、里面有一段自己还没读过的注释的东西。[关于上传文件的那篇更长的说理](https://abox.tools/zh/guides/is-it-safe-to-upload-files/)，在这儿和在本站任何地方一样成立。
