在桌面浏览器里打开 Google,搜任何技术问题,看每条结果左侧那一列。域名旁的小图就是 favicon。Google 在 2019 年开始在移动端 SERP 显示它,2024 年扩展到桌面 SERP。那一栏里没有可辨识 favicon 的站点显得像无人维护,有清晰品牌图标的站点显得专业。这枚 16 像素宽的小图,就在用户决定是否点击的位置出现。
这枚 16 像素的图标,也是少数几样能横跨浏览器标签、收藏栏、操作系统任务栏、iOS 主屏、Android PWA 安装、RSS 阅读器、桌面快捷方式的视觉元素。每一个场景需要的文件略微不同 — 尺寸不同,有时格式不同,有时还要自己的 manifest 条目。本文讲清现代 favicon 套件到底长什么样、为什么单一 favicon.ico 已经不够、每个文件在运行时承担什么角色,以及 ZeroTool 生成器如何在浏览器里把这一整套打好包,全程不上传任何字节。
现代浏览器到底请求了哪些文件
打开自己网站的 DevTools 刷新一次,看 Network 面板。一次干净的 Chrome 加载至少会命中三个:
| 请求 | 用途 | 备注 |
|---|---|---|
/favicon.ico | 老浏览器和先按规范文件名查找的收藏夹管理器的兜底 | 是一个多尺寸容器;现代浏览器为兼容也会继续请求 |
<link rel="icon" type="image/png"> 中 href 指向的 PNG | 现代浏览器优先选 sizes 匹配的 PNG | Chrome、Firefox、Safari 会挑最接近设备像素比的尺寸 |
<link rel="apple-touch-icon"> 中 href 指向的图 | iOS Safari,地址栏与「添加到主屏幕」均用 | 标准尺寸 180×180 |
在 Android Chrome 上把站点装成 PWA,请求列表会变长:
| 请求 | 用途 |
|---|---|
/site.webmanifest(或 manifest.json) | Chrome、Edge、Brave、Samsung Internet — 任何能装 PWA 的浏览器 |
manifest icons 数组里声明的 192×192 与 512×512 PNG | Android 主屏图标、启动画面、Android 分享面板 |
在那些 manifest 条目里加上 purpose: "any maskable",Android 会按启动器主题对图标应用圆形或圆角矩形蒙版,让图标在启动器网格里看起来像原生应用。Maskable 图标的可见标识周围需要约 10% 的安全区留白,否则启动器蒙版会切掉边缘。
还有那条长尾。Windows 磁贴曾经要 browserconfig.xml;微软在 Windows 10 中把这一标准弃用,今天已经不需要了。Safari 钉住标签页用的是 <link rel="mask-icon"> 上的单色 SVG。早期 PWA 之前的 Android Chrome 把 apple-touch-icon 作为兜底。这些到 2026 年都不是主流需求,但能解释为什么老的生成器一次出二十多个文件,而你真正想要的是十一个。
为什么单一 favicon.ico 已经不够
历史上的默认做法是把一个 ICO 放到站点根目录,让浏览器自己挑。当显示器最大 1280×1024、标签页只有 16 像素方块时,这够用。两件事破坏了这个默认:
- Retina 显示器。 浏览器把 16×16 的 ICO 放大到 32 逻辑像素显示在 2× 屏上时会糊。
<link rel="icon" type="image/png" sizes="32x32">让浏览器按设备像素比挑对的资源。 - 标签页之外的操作系统画布。 iOS dock 图标、Android 主屏磁贴、PWA 启动画面、Windows Edge 磁贴 — 每一个画布都按特定尺寸采样,没人想要 16 像素的 ICO。它们要 180、192、512,以及一份 manifest 告诉它们哪个文件对应哪个用途。
修法就是现代套件:兼容用的小 ICO、给现代 <link rel="icon"> 链路用的若干 PNG 尺寸、iOS 用的 apple-touch-icon、含 maskable PWA 图标的 webmanifest。
完整文件清单与各自的运行时角色
ZeroTool 生成器输出的就是这十一个文件,以及它们在运行时被谁用:
| 文件 | 尺寸 | 用在哪里 |
|---|---|---|
favicon.ico | 16+32+48 多尺寸 | 老浏览器、收藏夹管理器、「先请求规范文件名」的代码路径 |
favicon-16.png | 16×16 | 标准 DPI 显示器上的浏览器标签 |
favicon-32.png | 32×32 | Retina 显示器上的标签、部分收藏栏 UI |
favicon-48.png | 48×48 | Windows 站点快捷方式、部分 SERP 预览 |
favicon-64.png | 64×64 | 部分需要更密图标的地址栏 UI |
favicon-96.png | 96×96 | 没装 PWA 的 Android Chrome 快捷方式 |
favicon-128.png | 128×128 | 老版 Chrome web app 快捷方式 |
apple-touch-icon.png | 180×180 | iOS Safari「添加到主屏幕」、iPad dock |
android-chrome-192.png | 192×192 | 通过 PWA 装到 Android 主屏(manifest icon) |
android-chrome-512.png | 512×512 | Android 启动画面、分享面板、Play Store 风格卡片 |
site.webmanifest | text | 声明 192/512 PNG、主题色,以及 purpose: any maskable |
十一个文件。如果素材是 emoji 或简单 SVG,整个包约 25 KB;如果你拿一张 4K 图压到 512×512,包大小会到约 200 KB。
ICO 文件格式怎么工作
favicon.ico 是套件里最古怪的文件,因为它早于 PNG 出现 — 它生于 Windows 3.0,最初承载的是与设备无关位图(DIB / BMP)帧。如今多数生成器改用 PNG 压缩条目,Windows Vista 之后的资源管理器、IE 11 以及之后的所有浏览器都原生支持。PNG 压缩条目更小、保留 alpha 通道,格式也直白。
一个 ICO 文件是这样的:
ICONDIR (6 字节)
├── reserved (2 字节,零)
├── type (2 字节,1 = ICO,2 = CUR)
└── count (2 字节)
ICONDIRENTRY × count (每条 16 字节)
├── width (1 字节,0 表示 256)
├── height (1 字节,0 表示 256)
├── colorCount (1 字节,32 位时填零)
├── reserved (1 字节,零)
├── colorPlanes (2 字节,1)
├── bitsPerPixel (2 字节,32)
├── imageSize (4 字节)
└── imageOffset (4 字节 — 在 ICO 文件里的绝对偏移)
(各图像负载按顺序拼接在目录后面)
对 PNG 条目而言,imageSize 是一个完整 PNG 文件(含自身的 IHDR / IDAT / IEND chunk)的字节数,imageOffset 指向那个 PNG 的第一个字节。ICONDIRENTRY 里的 width/height 字段可以与 PNG 自身的宽高不一致 — 操作系统显示的尺寸来自 PNG 的固有尺寸,所以 ICONDIRENTRY 的值最多算建议值。让二者一致能让所有 shell 都满意。
ZeroTool 生成器把 16、32、48 三个 PNG 打进 ICO,没装更大的尺寸。理由是 Windows 工具几乎不会从老式 ICO 容器里挑超过 48 的图,更大的 PNG 已经通过现代 <link rel="icon"> 链路和 manifest 暴露出去。把 256×256 塞 ICO 是 apple-touch-icon 出现之前的老配方;2026 年这一职责由 apple-touch-icon 与 android-chrome PNG 接管。
ZIP 容器怎么工作
浏览器需要一种方法一次给用户十一个文件而不是触发十一次下载,所以生成器把它们打成 ZIP。ZIP 几十年来一直是默认容器,因为每个操作系统都不需要第三方工具就能打开。ZIP 内部分层:一系列「local file header + 负载」的序列,接一份「central directory」列出每条目,最后一条「end-of-central-directory」记录告诉读取方 central directory 从哪儿开始。
每条目的负载有两种编码方式:STORED(不压缩)或 DEFLATE。PNG 已经压缩过,再走一遍 DEFLATE 大约只能再省 0.5–1% — 不值得为此往页面包里塞一份 deflate 实现。ZeroTool 生成器对所有条目都用 STORED,省下了大约五千字节代码。
CRC-32 是 ZIP 规范里唯一不能跳过的部分。每条目都必须带未压缩字节的 32 位 CRC。生成器在脚本启动时预计算一张 256 项查找表,对每个文件的字节走一遍即可。文件名在 General Purpose Bit Field 的 bit 11 上声明为 UTF-8,这样在 macOS Finder、Windows 资源管理器和 7-Zip 里非 ASCII 名都能正确显示。
Canvas 管线
每个 PNG 的绘制都走相同的五步:
// 一个目标尺寸的伪代码
const canvas = createCanvas(size, size);
const ctx = canvas.getContext('2d');
if (shape !== 'square') {
drawShapePath(ctx, shape, size);
ctx.clip(); // 圆角 / 圆形的 alpha 蒙版
}
if (bgMode === 'color') {
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, size, size);
}
const inner = size * (1 - padding * 2);
drawSourceCentered(ctx, source, size, inner); // emoji / text / image / svg
const pngArrayBuffer = await canvasToPng(canvas);
canvas.toBlob('image/png') 干所有重活 — 缩放、抖动、alpha 编码。输出是一个完整的 PNG 负载,含 IHDR、一段或多段 IDAT chunk、以及 IEND。多数现代浏览器对 IDAT 默认用一档合理的 zlib 压缩;对一个 16×16 的图标,每个文件通常落在 200–400 字节。
有三种失败模式值得显式处理:
- 跨域 SVG 内容污染 canvas。 用户粘贴的 SVG 里若加载了
<image href="https://example.com/x.png">,浏览器会拒绝把像素读回为 blob。把canvas.toBlob包在 try/catch 里,给出清晰提示:「SVG 引用了外部资源,请先把图片内联」。 - 缺少彩色 emoji 字体。 部分 IT 管控的 Linux 发行版没装彩色 emoji 字体。Canvas 渲染出空白矩形,最终 PNG 是空方块。通过
ctx.measureText('🚀').width === 0检测,提示用户切换到 Image 或 SVG 输入。 - 4K 图配九个目标尺寸的内存压力。 串行生成、每个
toBlob都 await、字节读完立刻 revoke object URL。同时持有九张高分辨率 canvas 在内存里会让 iPad 上的 Safari 崩溃。
SVG、emoji 与跨平台一致性问题
最微妙的输出差异来自彩色 emoji 字体。macOS 自带 Apple Color Emoji,Windows 自带 Segoe UI Emoji,Android 与 Linux 桌面常见的是 Noto Color Emoji。同一个 Unicode 码点会渲染出三个明显不同的形状:
- 🚀 在 Apple Color Emoji 里是一只黄色火箭,带一扇细白窗户
- 🚀 在 Segoe UI Emoji 里更扁平,窗户颜色更深
- 🚀 在 Noto Color Emoji 里边缘更圆,阴影也不同
如果你在 macOS 上生成 favicon,访客从 Windows 访问也只看到你生成的那个 favicon — 字节已经烤进 PNG。Canvas 渲染器把 emoji 在开发者机器上呈现的样子捕获下来,然后把这些像素发给所有访客。所以选一台机器,生成一次,结果对之后所有访客都一致。一致性真正成问题的地方在开发者自己的迭代:六个月后在另一个操作系统上重新生成,会得到一个略有差异的 favicon。
要追求跨机器像素级一致,就切到 Image 或 SVG 输入。SVG 矢量图按其自身定义确定性地光栅化,与操作系统的字体栈无关。代价是 SVG 必须自包含 — 不能引远程资源的 <image href>、不能用外部 <use> 片段、不能用远程 @font-face。粘贴前把所有外部依赖都内联。
HTML 片段为你做了什么
生成器输出的片段如下,放进 <head>:
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon-48.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
<meta name="theme-color" content="#ffffff">
几个微妙之处:
- 顺序不像你以为的那么重要 — 现代浏览器会解析所有
<link rel="icon">候选,按sizes与type选最匹配的。把 ICO 放第一是惯例,不是要求。 <meta name="theme-color">控制移动端 Safari、Chrome 地址栏,以及已安装 PWA 的标题栏颜色。它不是 favicon,但因为住在同一个 head 段、共用品牌色决策,所以与 favicon 套件一起出现。- 文件名
site.webmanifest是惯例;不少教程用manifest.json。两者都可以。沿用项目其他位置已用的那个就好。 - iOS 不读 manifest icons — 它永远挑
apple-touch-icon。Android Chrome 在二者并存时优先选 manifest icons。
ZeroTool 与其他生成器的对比
RealFaviconGenerator 是长期标杆。它把源图上传到服务器,在服务端生成一份带更广老格式(Microsoft tile、Safari pinned-tab SVG、Windows 8 metro)的包,输出约 25 个文件。代价是上传步骤和更大的产出体积。
favicon.io 在精神上更接近 ZeroTool:输入简单(emoji、文字、图片)、包小、不上传。它当前不输出 webmanifest。
ZeroTool 生成器瞄准 2026 年的基线:十一个文件、含 maskable PWA 图标的 webmanifest、不上传服务器、可复制粘贴的 HTML 片段。如果你需要 Microsoft Tile 支持或 Safari pinned-tab SVG,RealFaviconGenerator 仍然是对的工具。如果只是给个人站点或内部仪表盘做一个 emoji 驱动的 favicon,ZeroTool 更快。
部署前 checklist
部署之前,请走一遍这几步:
- 把十一个文件放到站点根目录。 多数主机即使没有
<link>标签也会以 200 响应/favicon.ico,所以放根目录而不是/assets/icons/之下。 - 把 HTML 片段贴进
<head>。 ICO 是隐式被请求的,但 PNG 与 apple-touch-icon 需要显式<link>标签。 - 更新
site.webmanifest里的name与short_name。生成器把它们留空,避免你部署一个占位名。 - 用 DevTools 的 Application 面板测。 Application → Manifest 显示解析后的 manifest、解析得到的图标,以及任何错误。用 Chrome 的「Show maskable icon」开关测试 maskable 渲染。
- 测一遍 iOS 路径。 在真机 iPhone(或 iOS 模拟器)上「添加到主屏幕」,确认 apple-touch-icon 没有出现细白边。iOS 自动加圆角但不自动加底色 — 如果你的图标是透明背景,iOS 会填白色,在深色壁纸上可能看着别扭。
- 校验 Google SERP favicon。 Google 至少要求 8×8、推荐至少 48×48;多尺寸 ICO 两边都覆盖。用 Search Console(Coverage → Favicons 报告)确认。
- 品牌变了就重做。 把 favicon 套件当作一个构建产物,而不是一次性资产。把源文件(喂给生成器的 SVG 或高分辨率 PNG)纳入版本控制,标识或主题色变更时从同一源文件再生成。
隐私说明
因为整条管线都跑在浏览器里,你的源图任何版本都不离开本机。这件事比听起来重要:当你给一个未发布的产品生成 favicon 时,等于把品牌标识泄露给所用的生成器。RealFaviconGenerator 的隐私政策直白,但上传依然发生。ZeroTool 把图保留在本地。打开 DevTools → Network 后点 Generate — 只有一次出站请求,是非阻塞的统计上报,负载里只有工具名。
延伸阅读
- Apple 官方关于 apple-touch-icon 尺寸的「Configuring web content」指南
- W3C Web App Manifest 规范 — manifest icon
purpose取值的事实源 - web.dev:PWA 中的 Maskable 图标
- 微软对
browserconfig.xml的弃用说明 — 确认你不再需要 MS Tile 资源 - Google Search Central:在搜索结果中定义 favicon
- Apache ZIP 文件格式规范(PKZIP APPNOTE.TXT) — 想读完整 ZIP 布局的人
ZeroTool 站内相关工具:SVG 转 PNG 工具、WebP 转换器、图片转 Base64 工具、二维码生成器。