§ 2.2 · Section

位图 vs 矢量

Bitmap vs Vector

同一个 Logo,你把它放大十倍,一个变成了满屏的马赛克方块,另一个边缘依然刀切一样锐利。它们看起来是"同一张图",其实在计算机内部是两种完全不同的东西——一种存的是结果,一种存的是做法。搞清这个区别,你就明白了为什么设计师给你 SVG 而不是 PNG,也明白了为什么截图放大永远救不回来。

生活场景
🧵 十字绣成品 vs 十字绣图纸

你妈妈绣了一幅十字绣的猫,绣在一块 100×100 格的布上。
现在你想要一幅 400×400 格的大猫。
方案 A:把绣好的成品拍照,用放大镜投影到大布上照着描——每一格线变成 4×4 格,猫的轮廓变成了阶梯状的锯齿。
方案 B:你妈妈手里还有那张图纸,上面写着"耳朵是一个 30° 的三角形,眼睛是半径 4 格的圆"。拿图纸重新在大布上按比例绣一遍——大猫和小猫一样精致。

位图:一张巨大的颜色表格

位图的原理朴素到近乎粗暴:它就是一个像素矩阵。一张 1920×1080 的图片,本质上是一张有 1920 列、1080 行的表格,一共 2,073,600 个格子,每个格子里填了一个颜色值。文件里存的就是这两百多万个颜色值,按顺序排成一长串数字。

如果每个像素用 R、G、B 三个通道、每个通道 8 位(0~255)来记,那一个像素占 3 个字节;再加一个透明通道 A 就是 4 个字节。所以一张 1920×1080 的未压缩图片,理论大小是 1920 × 1080 × 4 ≈ 8.3 MB。你平时下载的图片只有几百 KB,是因为所有图片格式都做了压缩——这也是各种格式差异的核心来源。

位图最大的软肋,就来自"它只存结果"这个事实。图片里根本没有"这是一条直线"的概念,只有"第 300 行第 47 到 92 个格子是黑色"这种记录。当你要放大它,程序面对的是一道无解的题:原图只有 100 个格子的信息,现在要填 400 个格子,多出来的信息从哪来?只能靠猜——这个猜的过程叫插值(interpolation)。猜得再好也是猜,所以放大后必然发虚、发糊,或者出现阶梯锯齿。

Analogy · 冲好的咖啡 vs 咖啡配方

位图像一杯已经冲好的咖啡:你能直接喝,但想把它变成两杯,只能加水稀释——味道就淡了。
矢量图像一张写着"18 克豆、1:15 水粉比、92℃"的配方卡:想要两杯,按配方翻倍再冲一次,浓度分毫不差。
代价是:配方卡不能直接喝,得先冲(这一步叫栅格化,rasterize)。

常见位图格式对比:各有各的活

位图格式的区别,几乎全在"怎么压缩"这一件事上。压缩分两大流派:无损压缩(把数据换一种更紧凑的写法,解开后和原来一模一样)和有损压缩(丢掉人眼不敏感的细节,换取小得多的体积,且丢掉的永远回不来)。

格式压缩透明典型体积最适合
PNG无损支持(8 位 Alpha)截图、UI 切图、需要透明的素材、纯色/线条图
JPG有损不支持照片、复杂渐变的实拍图
WebP有损 + 无损两种模式支持比 JPG 小 25~35%网页通用主力,现代浏览器全支持
AVIF有损 + 无损支持比 WebP 再小 20~50%追求极致体积的网页大图,编码较慢
GIF无损但限 256 色只有"全透/全不透"动图偏大已过时的简单动图,现在应换成视频或 WebP

逐个说清它们的性格:

网页里最推荐的做法是让浏览器自己挑它能吃的那一种,前面的格式优先,不支持就往后退:

<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="首页主图" width="1200" height="630">
</picture>

浏览器从上往下试:认识 AVIF 就用 AVIF,不认识就看 WebP,都不行才落到最后那个 <img>。这样新设备享受小体积,老设备也不会白屏。

矢量:存的是"怎么画",而不是"画成什么样"

矢量图彻底换了个思路:它不记录任何像素,而是用数学描述图形的构造方式。一个圆,它记的是"圆心在 (50, 50),半径 40,填充红色";一条曲线,它记的是几个控制点和一段贝塞尔曲线公式。文件里全是坐标和参数,没有一个像素。

这带来一个近乎魔法的性质:因为它存的是公式,所以在任何尺寸下都可以现场重新算一遍、重新画一遍。放大 100 倍?把所有坐标乘 100,重新算,边缘依然是完美的数学曲线。这就是"矢量图无限缩放不失真"的全部秘密——它不是"压缩得好",而是根本没有分辨率这个概念

当然,屏幕本身是像素做的,最终还是得把矢量变成像素才能显示。这个"按当前尺寸现场算出像素"的动作叫栅格化。关键区别在于:位图是出厂时就栅格化好了,矢量图是每次显示时按当前需要的尺寸重新栅格化。前者一次成型无法回头,后者永远新鲜。

SVG:网页里的矢量标准

网页上的矢量格式叫 SVG(Scalable Vector Graphics,可缩放矢量图形)。它有个非常特殊的身份:SVG 不是二进制图片文件,它是一段 XML 文本——你能用记事本打开它、读懂它、直接改它。

<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <!-- 一个圆:圆心 50,50 半径 40 -->
  <circle cx="50" cy="50" r="40" fill="#556b3d"/>
  <!-- 一条折线路径:M 移动到, L 画直线到 -->
  <path d="M30 55 L45 70 L72 38"
        stroke="#fff" stroke-width="8"
        fill="none" stroke-linecap="round"/>
</svg>

这十来行文本就是一个"绿底白勾"的对号图标,无论显示成 16px 还是 1600px 都同样锐利,而文件只有两百来个字节。里面几个关键概念值得记住:

因为是 DOM,改颜色就跟改文字颜色一样简单:

/* 让图标自动跟随按钮文字颜色 */
.btn svg { width: 1em; height: 1em; fill: currentColor; }
.btn:hover { color: #a05a2c; }   /* 图标也一起变色 */

什么时候用哪种:一条清楚的分界线

判断规则其实非常简单,问自己一句话:这张图能不能用有限条几何指令描述清楚?

还有一个常被忽略的现实理由:矢量图不需要准备 @2x / @3x 三份。上一节讲过,位图要在高清屏上清晰,必须准备多倍图;矢量图天生适配任何像素密度,一份文件通吃所有屏幕,工程和设计的维护成本直接砍掉三分之二。

图标方案的三次进化

"怎么在界面里放图标"这个小问题,行业整整折腾了二十年,正好是位图与矢量之争的活化石。

第一代 · 图片切图(PNG Sprite)

每个图标切成一张小 PNG。图标一多,页面就要发几十个网络请求,于是发明了"雪碧图"——把几十个图标拼成一张大图,再用 background-position 把需要的那一小块露出来。问题:换颜色要重新出图,换尺寸就模糊,高清屏还得再出一套 @2x,改一个图标要重新拼整张图。

第二代 · 字体图标(Icon Font)

聪明的取巧:把图标画成"字",做成一个字体文件,用一个特殊字符来"打出"图标。因为字体本身就是矢量的,于是图标突然可以任意缩放、可以用 color 直接改色、可以加 text-shadow。代价也很真实:图标被当成文字,字体没加载完会闪出方框或乱码;无法做多色图标;对屏幕阅读器不友好,会念出奇怪的字符。

第三代 · SVG(今天的标准答案)

直接把矢量图形放进页面。多色、渐变、局部动画、无障碍标签(<title>)全都支持,可以按需只加载用到的那几个,还能用 <symbol> + <use> 做复用。现在几乎所有主流图标库都以 SVG 为第一交付格式。

SVG 复用的经典写法是把所有图标定义在页面里一次,之后到处引用:

<!-- 定义一次(可以藏在页面顶部) -->
<svg style="display:none">
  <symbol id="i-check" viewBox="0 0 24 24">
    <path d="M4 13l5 5L20 7" stroke="currentColor"
          stroke-width="2" fill="none"/>
  </symbol>
</svg>

<!-- 之后任意处引用,想用几次用几次 -->
<svg class="icon"><use href="#i-check"/></svg>

几条能立刻用上的实用建议

一个容易混淆的点:分辨率无关 ≠ 无限精细

矢量图"无限放大不失真"说的是已有的几何信息在任何尺寸下都能精确重绘,不是"能凭空长出更多细节"。一个只用 8 条直线画成的粗糙图标,放大到墙那么大,依然是那个只有 8 条边的粗糙图标——只不过每条边都很锐利。矢量解决的是清晰度问题,不解决细节量问题。同理,把位图用工具"转成矢量"(描摹)只是让程序去猜边界并生成路径,猜错了就会变形,这不是真正的还原。

Recap · 收束

位图存结果,矢量存做法——这一句话是本节的全部。位图是一张写满颜色值的巨型表格,出厂即定型,放大只能靠猜,所以会糊;它的各种格式(PNG/JPG/WebP/AVIF/GIF)差别几乎全在压缩策略上,选错格式就是白扛体积或白丢画质。矢量是一份几何配方,每次显示都按当前尺寸重新算一遍,因此天然适配所有屏幕密度,一份文件通吃 @1x 到 @3x。凡是能用形状描述清楚的(图标、Logo、图表)就上 SVG,凡是真实世界拍下来的(照片、纹理)就用位图。剩下的功夫,就是给每种图选对格式、压对大小、写好宽高。

☰ 主页
学海无涯 · 界面篇 · § 2.2