你上传了一个完美的 logo,把系统切到深色模式,打开网站——结果看到亮橙色的品牌标记在深色标签栏上刺眼地反光。普通的 PNG favicon 无法感知系统主题。但带有内置 prefers-color-scheme 媒体查询的 SVG favicon 可以。

本指南聚焦一种特定技术:把 CSS 媒体查询直接嵌入到 .svg 文件内部,让单一文件自动切换配色。这条路径不同于在 HTML 里换两个 <link> 标签——对大多数网站来说,它是最干净的方案。

前置条件

开始之前,你需要三样东西:

如果还没有 SVG,可以从设计工具导出一个,或者用 Mzu favicondl 从任意图片中提取干净的矢量版本。

分步操作:在 SVG Favicon 中加入媒体查询

第 1 步:用文本编辑器打开 SVG 文件

SVG 本质就是 XML。右键任意 .svg 文件,选择打开方式 → TextEdit 或 VS Code。你会看到类似这样的内容:

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'>
  <rect width='64' height='64' rx='12' fill='#ff7a00'/>
  <path d='M20 22 L32 44 L44 22' stroke='#fff' stroke-width='6' fill='none'/>
</svg>

第 2 步:添加带媒体查询的 <style> 块

在开头的 <svg> 标签之后,立刻插入一个 <style> 元素。在里面定义浅色主题的颜色,再用 prefers-color-scheme: dark 在深色模式下覆盖它们:

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'>
  <style>
    .bg { fill: #ff7a00; }
    .stroke { stroke: #ffffff; }
    @media (prefers-color-scheme: dark) {
      .bg { fill: #1a1a1a; }
      .stroke { stroke: #ffb347; }
    }
  </style>
  <rect class='bg' width='64' height='64' rx='12'/>
  <path class='stroke' d='M20 22 L32 44 L44 22' stroke-width='6' fill='none'/>
</svg>

浏览器会在每次系统主题变化时重新评估 prefers-color-scheme。在大多数现代浏览器里,你的 favicon 不用刷新就能更新。

第 3 步:在 HTML 的 <head> 中链接它

根据 WHATWG HTML 现行标准,rel='icon' link 类型在你声明了 type='image/svg+xml' 这个正确的 MIME 类型时是支持 SVG 的:

<link rel='icon' href='/favicon.svg' type='image/svg+xml'>

把它放在任何 PNG 或 ICO 备用文件之前。可以参考我们的 favicon HTML 速查表,里面列出了完整的现代写法,包括 Apple Touch 和 web manifest 条目。

第 4 步:提供栅格图备用方案

并非所有浏览器都能解析 favicon 内部的 CSS——比较典型的就是旧版 Safari 和某些嵌入式 web view。为这些客户端准备一张 32×32 PNG(或一个多尺寸 ICO):

<link rel='icon' href='/favicon.svg' type='image/svg+xml'>
<link rel='icon' href='/favicon.ico' sizes='32x32'>

浏览器按顺序匹配第一个能用的,所以在支持 SVG 的环境下 SVG 优先。

第 5 步:在两种配色下分别测试

强制硬刷新(Ctrl/Cmd + Shift + R),然后切换系统主题。在 Chrome、Edge 和 Firefox 里,标签图标应该会实时切换。如果没反应,跳到下面的坑点部分。

常见坑点

坑点 1:忘了写 viewBox

没有 viewBox,SVG 会按固有尺寸渲染,可能是巨大的,也可能为零。一定要声明一个:viewBox='0 0 64 64'。

坑点 2:内联 fill 属性会覆盖你的 CSS

如果你的图形已经带了 fill='#ff7a00' 这种属性,你的 CSS 类在特异性上会输掉。把颜色挪到 class 里,或者干脆删掉那个内联属性。

坑点 3:favicon 缓存过于顽固

浏览器对 favicon 的缓存力度几乎超过任何其他文件。改完 SVG 之后,测试时给它追加一个查询字符串:/favicon.svg?v=2。我们的缓存清理指南里有生产环境的应对策略。

坑点 4:Safari 固定标签页忽略媒体查询

Safari 的固定标签页功能用的是单独的单色 safari-pinned-tab.svg。这个文件里的媒体查询不会生效。把图标设计成单色剪影即可,跳过 <style> 块。

坑点 5:深色模式不等于反色

挑选一套深色模式配色,要让它和浏览器实际的标签背景之间真有对比度(Chrome 通常是 #2b2a33,Safari 接近纯黑)。用对比度检查工具跑一遍图标,能省下后续一堆支持工单。

小结

SVG 媒体查询这条路给你一个权威来源:一个文件,两套主题,零 JavaScript。对于已经拥有 SVG logo 的现代站点来说,这就是默认的正确选择;同时它并不排斥你仍然要提供的 PNG 和 ICO 备用方案——两者是并存的,不是对立的。

核对文档中的相关要求

HTML 标准把 rel='icon' 定义为表示当前页面图标的 link 关系。