# iOS 不会用 SVG 格式的 apple-touch-icon

> 一篇 dev.to 报告发现某 PWA 把 apple-touch-icon 声明为 SVG，报告说 iOS 改用页面截图，另有一个只标了 maskable 的 manifest 图标。

2026-10-06，dev.to 账号 daniel_pertu 发表了一篇关于 pub-trivia.app 安装面的报告。
pub-trivia.app 是一个面向酒吧问答之夜的 Web 应用，而这篇报告的主题是一处构建链里每个工具都
接受、iOS 却不会使用的图标声明。报告写明该站点声明了
`<link rel="apple-touch-icon" href="/icon.svg">`，而 iOS 在这里期望的是一个 PNG；交给它一个
SVG，它会忽略这条声明并回退为一张页面快照，于是主屏幕条目在本该是 logo 的位置显示的是落地页
的截图
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

## 这篇报告检查了什么

报告基于它自己取回的公开产物：该应用的 manifest，以及它文档 head 里的图标声明，并连同生成它们的
`curl` 命令一起印了出来。下面按顺序逐条列出它的发现，用的是报告本身以及它所涉及的文档的措辞
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

### 报告印出的 manifest

报告印出了 pub-trivia.app 的整份 manifest，是用
`curl -s https://pub-trivia.app/manifest.webmanifest` 取回的。它展示的对象里，`name` 与
`short_name` 都是 `PubTrivia`，`description` 是
"Live pub quiz nights, scan, join, play!"，`start_url` 是 `/`，`display` 是 `standalone`，
`background_color` 与 `theme_color` 都是 `#171717`，`icons` 数组只有一个条目：`/icon.svg`，
`sizes` 为 `any`，`type` 为 `image/svg+xml`，`"purpose": "maskable"`。报告自己对这份输出的
清点是七个字段、一个图标，没有 screenshots、没有 shortcuts、没有 categories，也没有 `id`
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

报告给出的"为什么这么小"的理由是：manifest 服务的是安装该站点的人，而这个应用有两类受众，其中
只有一类会安装。它描述一位玩家扫桌上的码进来、玩一个晚上、再也不回到那个 URL；以及一位主持人
每周打开同一个站点，通常用吧台后面同一台笔记本或平板。对主持人来说，报告把独立窗口称为一项真实
的改善，点名不会有地址栏被误触、也不会有标签页在一轮中途被别人关掉；并由此得出结论：
`display: standalone` 是为每个场地恰好一位用户而存在的
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

接着报告为这个对象背后的字段选择作了辩护。关于 `start_url`，报告写明它是 `/` 而不是 `/dashboard`，因为让
已安装应用直接启动进 dashboard 在用户已登录时更好、未登录时更糟，因为那时应用一打开就是一次到
登录表单的重定向，而落地页能同时应付这两种状态。关于 `theme_color`，报告写明这个值出现了两次，
一次在 manifest 里，一次作为文档 head 中的 `<meta name="theme-color">` 元素；并写明这不是失误：
manifest 里的值在站点被安装时生效，而 meta 标签作用于普通访问时的浏览器界面，而普通访问正是每位
玩家的访问
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

MDN 记录了这两套主题色机制之间的关系。MDN 写明 `theme_color` 成员用于指定 Web 应用用户界面的
默认颜色，该颜色可能被应用到各种浏览器 UI 元素上，例如工具栏、地址栏与状态栏，并且在任务切换器
这类上下文中、或当应用被添加到主屏幕时尤其显眼。MDN 写明在支持 `theme_color` 的浏览器中，
manifest 文件里指定的值会作为该 Web 应用在所有应用了该 manifest 的页面上的默认主题色，而这个
默认值可以通过 HTML `<meta>` 元素 `name` 属性的 `theme-color` 值覆盖，从而为应用内的单个页面
设置不同的主题色
([MDN，theme_color](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/theme_color))。

### iOS 真正读取的那条图标声明

报告印出了页面发出的图标声明，是通过 grep 已提供的 HTML 得到的：一条
`<link rel="manifest">`，一条指向带指纹的 `favicon.ico` 且带 `sizes="200x200"` 与
`type="image/x-icon"` 的 `<link rel="icon">`，第二条指向 `/favicon.svg` 的
`<link rel="icon">`，以及 `<link rel="apple-touch-icon" href="/icon.svg">`。报告把最后这一行
认定为缺陷，写明 iOS 不会为主屏幕图标去读 manifest，它读的是 `apple-touch-icon`，并且期望一个
PNG，按惯例是 180 乘 180。它对交给 SVG 会发生什么的说法是：iOS 并不会优雅地缩放你的矢量 logo，
而是忽略这条声明并回退为一张页面快照，于是把站点添加到主屏幕的人得到的是落地页的一张又小又模糊
的截图。报告给出的修法是一张 180 乘 180 的 PNG 加一处改掉的 `href`
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

报告把 webhint 的 `apple-touch-icon` hint 作为它关于 iOS 行为的来源，而那条 hint 写明了这个问题
的两半。它写明 `apple-touch-icons` 要求至少存在一个 Apple touch icon 且为标准尺寸之一，并写明
自 iOS 1.1.3 起，Safari for iOS 就支持一种让开发者指定用于在主屏幕上代表该网站或应用的图像的
方式，这个图像被称为 touch icon。在 manifest 这个问题上，它写明自 iOS 11.1.0 起，Safari for iOS
支持 Web 应用 manifest 文件，该文件提供了一种标准、跨浏览器的方式来定义（除别的之外）浏览器可在
各种上下文中使用的图标；但它写明 Safari 依然忽略 Web 应用 manifest 中定义的图标，仍然使用非标准
的 `apple-touch-icon`
([webhint，Use Apple touch icon](https://webhint.io/docs/user-guide/hints/hint-apple-touch-icons/))。

该 hint 也给出了报告里那个 SVG 未能满足的格式与尺寸规则。它写明它会检查 `<head>` 中是否存在一条
或多条 `apple-touch-icon` 声明，以及：每条都带 `rel="apple-touch-icon"`、每个被声明的图像都可
访问且不会返回 404、每个被声明的图像都是它所列分辨率之一的 PNG。它归于 Apple 当前指南的那些
分辨率是：iPhone 为 180px × 180px，iPhone X 与 Plus 为 120px × 120px，iPad Pro 为
167px × 167px，iPad 与 iPad mini 为 152px × 152px。它把"被声明的图像不是 PNG"以及"被声明的
图像不是上述尺寸之一"都列在会触发该 hint 的示例中
([webhint，Use Apple touch icon](https://webhint.io/docs/user-guide/hints/hint-apple-touch-icons/))。

该 hint 里还有两处细节关系到 touch icon 该怎么声明。它写明不在页面中声明 touch icon、而只是把它
放在站点根目录，是不被推荐的做法，因为 Apple 可能更改默认请求的内容；并写明在只用一个图像时没有
必要使用 `sizes` 属性。它还写明在较旧版本的 Safari for iOS 中，可以用 `precomposed` 关键字阻止
iOS 给 touch icon 添加视觉效果（它点名圆角、投影与反光），而自 iOS 7 起不再对 touch icon 应用任何
特殊效果，因此已无需使用 `precomposed`
([webhint，Use Apple touch icon](https://webhint.io/docs/user-guide/hints/hint-apple-touch-icons/))。

### 只有一个 purpose 的那个 manifest 图标

报告的第二处发现是：唯一的那个 manifest 图标只声明了 `"purpose": "maskable"`，别的什么也没有。
报告把 maskable 描述为意味着该图像把重要内容放在安全区之内，于是启动器可以把它裁切成该平台使用
的任何形状（它点名圆形、squircle 与圆角方形），并称它是一项关于留白的承诺。它的论点是：把这个
作为唯一 purpose 来声明，等于没有任何一条条目说明该图标在不被裁切时应该是什么样子，于是想要一个
普通图标的那些面只能从一个 maskable 图标里挑；而一个 maskable 图标被不加蒙版地使用时往往显得又
小又飘，因为那些在圆形裁切下保护 logo 的留白，在没有东西裁切它时只是空白边距。报告称为正确的
形状是两条条目指向两个文件，一条 `purpose: "any"`、一条 `purpose: "maskable"`，并以不同的留白
量绘制，理由是它们本就是两幅不同的图像，而不是一幅图像用两次
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

MDN 对这两个关键字的定义支持这种读法。MDN 写明 `purpose` 是一个大小写敏感的关键字字符串，用于
指定浏览器或操作系统可以在哪一个或哪几个上下文中使用该图标；若省略，浏览器可以把该图标用于任何
用途；并写明浏览器把这些值当作提示，用来判断图标在何处以及如何显示。MDN 把 `maskable` 定义为
表示该图标在设计时已考虑图标蒙版与安全区，使得图像在安全区之外的任何部分都可以被忽略并被遮掉；
把 `any` 定义为表示该图标可在任何上下文中使用，并写明这是默认值。MDN 还写明在带多个关键字时，
浏览器可以把该图标用于其中任何一种用途，所以如果那确实是意图，单个文件也可以同时承载两项声明
([MDN，icons](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/icons))。

MDN 另外记录了该 manifest 所用的 `sizes` 值。它写明对 PNG 这类位图格式，推荐写明确切可用的尺寸；
对 SVG 这类矢量格式，可以用 `any` 来表示可缩放，而这正是报告那条 manifest 条目所带的值。它还写明
指定 `type` 属性可以显著改善性能，因为这让浏览器更容易忽略不支持格式的图像；而省略它时，浏览器
可能需要用更耗资源的方法来推断图像格式，例如对文件做 MIME 嗅探以寻找特征
([MDN，icons](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/icons))。

### 报告选择不动的那一项

第三项是带 `sizes="200x200"` 的 `favicon.ico` 声明。报告写明该文件是由 `app/` 中的文件生成的，
200 乘 200 不是一个惯常的 favicon 尺寸，所以它大概是该文件内部那张位图实际的量度。报告写明它能
用，浏览器会缩放它；并写明它要用 4.4 KB 去投递一张显示在 16 像素处的图像，而旁边那张 1 KB 的 SVG
在任何尺寸上都会更锐利；还写明这个 `.ico` 之所以还在，唯一的理由是为了那些太旧、吃不下 SVG 的
客户端。报告把它留在原处并记下一笔，给出的理由是"能用但略有不对"是 favicon 配置的自然状态
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

## 对 PWA 开发者为什么重要

报告的核心观察关乎反馈，而不是图标。它写明构建流程里没有任何东西对那个 SVG touch icon 发出警告：
文件可以解析、内容类型正确、SVG 在其他任何地方都渲染得完美、浏览器不报任何错误，于是这处失败只
出现在一台实体设备上、出现在主屏幕上。推而广之，它写明 manifest 与图标声明是 Web 应用里唯一一个
角落：你工具链的每一层都会对一份并不工作的配置报告成功；没有类型可以写错、没有请求会 404、也没有
控制台警告；而消费该文件的平台并不是你正在其上构建的平台，它会悄悄地回退到某种看起来合理的东西
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

有文档记载的行为解释了为什么只审 manifest 抓不到它。webhint 写明 Safari for iOS 自 iOS 11.1.0
起支持 Web 应用 manifest，但忽略其中定义的图标，仍然使用非标准的 `apple-touch-icon`；这意味着
一个正确的 `icons` 数组并不能作为 iOS 主屏幕会显示什么的证据。这也正是 webhint 的检查写在
`<head>` 声明上、而不是写在 manifest 上的原因：在 `<head>` 中存在且带 `rel="apple-touch-icon"`、
被引用图像可访问、以及为其所列分辨率之一的 PNG 格式
([webhint，Use Apple touch icon](https://webhint.io/docs/user-guide/hints/hint-apple-touch-icons/))。

manifest 这一侧有同样的性质，只是出于不同的原因。MDN 把 `purpose` 的各个值描述为浏览器用来判断
图标在何处以及如何显示的提示，并把 `maskable` 描述为一项声明，表示该图像在设计时已考虑图标蒙版
与安全区。两者都无法从 manifest 本身核实：这个关键字断言的是图稿排版方面的某件事，而 MDN 对安全
区的定义正是让这项断言有意义、而不只是装饰的东西。报告给出的规则由这两半共同推出，它写明：任何
只有操作系统这一个消费者的文件，都要在那个操作系统上、由人手工、在真实设备上核实一次；它还给出
一套具体做法：在 Safari 中打开该站点，分享，添加到主屏幕，然后看结果
([该报告](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef))。

## 站内相关条目

- [Capabilities](/zh/reference/capabilities/)：可沿此交叉链接继续阅读，并对照报告中对安装、主屏幕
  图标、manifest 与文档 head 声明的讨论。
- [Performance](/zh/reference/performance/)：报告拿一张显示在 16 像素处、4.4 KB 的 `.ico` 与一张
  1 KB 的 SVG 相权衡，而 MDN 写明声明图标 `type` 可以让浏览器跳过 MIME 嗅探；可沿此交叉链接
  继续阅读并对照这些细节。
- [Storage](/zh/reference/storage/)：可沿此交叉链接继续阅读，并对照所引材料中对 manifest 与触摸
  图标声明、图标选择和显示上下文的讨论。

## 待核实与存疑之处

- 当 `apple-touch-icon` 指向一个 SVG 时，iOS 是否正是回退为页面截图、而非回退为别的某种默认，
  这一点由报告断言；webhint 只写明该图标必须是受支持分辨率之一的 PNG，并未描述任何回退。
- 报告所观察到的那个主屏幕结果是在哪些 iOS 与 Safari 版本上得到的，并未说明。
- 如果同时声明了一个 PNG touch icon，`/icon.svg` 是否还会被 iOS 使用，未被涉及。
- 报告关于 maskable 图标在不加蒙版使用时显得又小又飘的描述，是否对应某个具体启动器的行为，
  未经确认。
- 报告推断 `.ico` 文件内部那张位图是 200 乘 200，这一点是报告作为推测提出的，不是测量结果。
- manifest 在那条 SVG 条目上写的 `sizes: "any"` 是否影响哪些面会选中该图标，报告未涉及。

## 参考来源

- [Our apple-touch-icon is an SVG, so iOS has been using a screenshot of the page instead](https://dev.to/daniel_pertu/our-apple-touch-icon-is-an-svg-so-ios-has-been-using-a-screenshot-of-the-page-instead-25ef)（dev.to）
- [Use Apple touch icon](https://webhint.io/docs/user-guide/hints/hint-apple-touch-icons/)（webhint.io）
- [icons](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/icons)（developer.mozilla.org）
- [theme_color](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/theme_color)（developer.mozilla.org）