你刚把一个清晰的 SVG favicon 推到线上,刷新标签页,Chrome 看着挺漂亮。但同一个站点在 Safari 里打开,显示的却是一片空白文档图标。问题其实不在 SVG,而在于它后面那条缺失的回退链路。
所谓 favicon fallback strategy,就是你在站点里同时放置的一组分层图标文件以及对应的 HTML link 标签,目的是让任何浏览器、任何标签页、任何设备都能展示出一个可识别的图标。与其赌某一个格式能通吃,不如提供一串候选:浏览器按顺序尝试,匹配不上就回退,直到有一个能用。
什么是 Favicon 回退策略
它就是在你的 <head> 里按照特定顺序摆放多种图标格式,同时把对应的文件也准备好。每一层存在的理由,都是上一层在某个场景下撑不住——老浏览器跳过 SVG,高清标签页把 16×16 的 PNG 糊成一团,移动主屏不认光栅化的 ICO。一个完整的策略要回答的问题是:“这个文件如果加载不出来怎么办?” 而不是在事故发生之后再去补救。
为什么浏览器需要回退链
没有哪一种图标格式能覆盖所有场景。SVG 可以无损缩放,但并不是所有老浏览器都会去请求它;PNG 几乎到处能用,却没法把多个分辨率打包进同一个文件;ICO 是浏览器的老牌容器格式,至今仍会主动去站点根目录请求 /favicon.ico,而且它依然是唯一一种“无需 HTML 提示也能被所有桌面浏览器识别”的格式。
除了格式差异,图标出现的场景也各不相同:浏览器标签页、书签栏、固定标签、移动主屏、新标签页快捷方式、Google 搜索结果、PWA 安装弹窗。每一个场景都有自己的尺寸要求、配色规则和文件格式偏好。一个合格的策略要同时照顾到这些,而不仅仅是那个 16×16 的标签页图标。
浏览器的选择逻辑
HTML 规范规定了浏览器如何从你的 <link rel='icon'> 标签里挑图标。浏览器会按顺序遍历列表,再结合 type、sizes、media 这几个属性挑出最匹配的一项。如果一个都没匹配上,它会回退到 WHATWG link 关系规范 中定义的 /favicon.ico 这个隐式请求。
由此可以推出两条实战经验:
- 顺序很关键。能力最强的文件(SVG)放最前面,能力弱的放后面。除非某个标签本身是无效的,否则浏览器不会跳着往后选。
type属性只是提示,不是门槛。如果浏览器解析不了image/svg+xml,它会去请求下一个图标,而不是直接放弃。
搭建一个稳健的回退栈
一套完整的策略通常包含四层,每一层都补上前一层覆盖不到的场景。
1. 现代层:SVG(可选地搭配 dark-mode media query)
SVG 在高清屏上缩放无压力,文件内部还可以直接写 prefers-color-scheme media query。建议放在 <head> 的最前面,让支持 SVG 的浏览器第一时间拿到它。
2. 通用层:32×32 与 96×96 的 PNG
PNG 是给那些忽略 SVG 的浏览器兜底用的。32×32 覆盖普通标签页和书签栏,96×96 照顾高密度屏幕,也满足 Google 推荐的最低尺寸。关于尺寸的取舍,可以参考 Favicon 尺寸指南。
3. 兼容层:把 16、32、48 三种分辨率打包进同一个 ICO
不少浏览器会无视你的 link 标签,直接去站点根目录请求 /favicon.ico。准备一个多分辨率的 ICO 文件正好接住这个隐式请求,避免控制台里刷出一片 404。具体的格式细节可以看 ICO 文件格式指南。
4. 平台特化层:Apple Touch、manifest、Safari pinned tab
iOS 主屏需要一张不带透明通道的 180×180 PNG;Android 则依赖 manifest 里 192 和 512 的图标条目;Safari 固定标签想要的是单色 SVG。这些都不是在替换你的回退链,而是在为它补齐边缘场景。
一个最小化的 HTML 模板
<link rel='icon' href='/icon.svg' type='image/svg+xml'>
<link rel='icon' href='/icon-96.png' sizes='96x96' type='image/png'>
<link rel='icon' href='/icon-32.png' sizes='32x32' type='image/png'>
<link rel='icon' href='/favicon.ico' sizes='any'>
<link rel='apple-touch-icon' href='/apple-touch-icon.png'>
<link rel='mask-icon' href='/safari-pinned.svg' color='#000000'>
注意这里是有讲究的顺序:SVG 在前(现代浏览器),PNG 居中(通用兜底),ICO 殿后(兼容老请求)。上一层被忽略时,下一层会自然接管。
常见的坑
- 完全省掉 ICO 文件。有些浏览器不管你写没写 link 标签,照样会去请求
/favicon.ico。 - 只准备一种 PNG 尺寸。16×16 的 PNG 在高清标签页上会糊成一团,而且达不到 Google 的最低尺寸建议。
- 把顺序写反了。如果 PNG 排在 SVG 前面,Chrome 明明能吃 SVG,也会先把那个光栅文件下载下来。
- 忘了加 cache-busting。老浏览器对 favicon 的缓存非常固执,标准的 querystring 技巧写在 favicon cache-busting 指南 里。
验证回退链是否生效
策略好不好,最终要靠验证来收口。打开 DevTools,把 Network 面板过滤到 img,确认浏览器真正请求的就是你期望的那张图。像 Mzu favicondl 这类工具也能直接抓取已上线的站点,把它识别到的所有图标——SVG、PNG、ICO、manifest、Apple Touch——罗列出来,方便你在用户发现之前先把缺口堵上。
目标并不是在某一款浏览器上做到完美,而是让每一个浏览器、每一个场景、每一次访问都能稳定显示一个可识别的图标。这才是真正的回退策略该有的样子。