在2021应该怎样配置 Favicon:用六个文件来适配大多数需求

翻译 笔记

本文最后更新于 <span id="expire-date"></span> 天前,文中部分描述可能已经过时。

翻译已获得原文作者许可,禁止转载和商用

是时候重新思考如何为现代浏览器配置一套 favicon 并且阻止发疯的图标生成器。今天,仅仅只是为了在浏览器 tab 栏和触控屏上显示一个小小的网站 logo,前端开发者就必须处理二十几个静态 PNG 文件。请继续阅读,看看如何使用更聪明方法来获得一套符合现代大多数需求的最小图标集。

原文链接: How to Favicon in 2021: Six files that fit most needs — Martian Chronicles, Evil Martians’ team blog
作者: Andrey Sitnik
站点: Evil Martians ——位于纽约和俄罗斯的 Ruby on Rails 开发人员博客。它发布了许多优秀的文章,并且是不少 gem 的赞助商。

事实证明,favicons 是个像大家期待一样的详尽主题,所以我也为那些受够了且确切知道怎么做的人用两个代码段对这篇文章做了总结。不过,我还是推荐大家阅读余下的内容!

太长不看版

你需要的只有 5 个图标和一个 JSON 文件,而不是十几个图标

在你的 HMTL 中添加这些:

<link rel="icon" href="/favicon.ico"><!-- 32×32 -->
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png"><!-- 180×180 -->
<link rel="manifest" href="/manifest.webmanifest">

并且在你的 web app manifest 中添加这些:

// manifest.webmanifest
{
  "icons": [
    { "src": "/192.png", "type": "image/png", "sizes": "192x192" },
    { "src": "/512.png", "type": "image/png", "sizes": "512x512" }
  ]
}

这样一切就做完了。如果你想知道我是如何做出这个结论的,对此我做出的妥协,以及如何从零开始一步步制作这样的图标包,请继续阅读下去。

完整版,一切问题都有解答。

favicon 这个概念,是「favorite icon」的简称,从2000年初便出现了。我们每天都可以在浏览器的标签页上看到这些可爱的小图片,它们可以帮助我们区分打开的不同网站。用户会希望你的网站有一个 favicon。这就是那些让别人认真看待你的小事情中的一件。

即便一直以来不喜欢那些不是源于 Cupertino 的图标设计且多年来在 Safari 中淡化 favicon 存在的 Apple 公司,也终于放弃了先前的行为,现在在所有设备上正确显示 favicon 了。

如果你有个面向公众的网站,那么它必须有一个 favicon。遗憾的是,用户所感知到的一个图标的背后其实是很多个图标。

因此,大家通常会把为不断增加的屏幕和设备列表生成必要文件的艰巨任务交给 favicon 生成工具。没有正常人会花好几小时去手动创建这些文件。我们是为了搭建网站,而不是为了让浏览器厂商开心。

A set of favicons generated by a popular online generator

作为 NanoID 的作者和极简开源的拥护者,我倾向从稍微不同的方向思考。什么样的网站图标集是最有效的?有哪些格式是过时的?有哪种类型的图标能够以最小的代价替换?

所以我开始创建一套最小的 favicon 集,它能够在所有情况下和所有浏览器中正常工作,除了一些边缘情况,但它仍可以工作,只是没有 100% 完美。

终极的 favicon 设置

与其创建不同大小的图片,我决定依靠 SVG 及浏览器缩放。如果你在意性能表现,这儿是我的解释:

  • 浏览器会在后台下载 favicon,所以更大的 favicon 图片并不影响网站的性能表现;
  • 使用 SVG 格式是减小图片(矢量图)大小的好方法;对于大多数 Logo 来说,使用 SVG 会比使用 PNG 时体积小很多;
  • 这个最小化的图标集只有三个 PNG 图片,你能够使用高级工具来优化它们的大小。这样子为那些没有无限数据套餐的因特网用户解决了一个问题。

这就是我在研究和实践中得出的最小图标集。它应该可以在所有流行的浏览器和设备中正常工作。

I. favicon.ico 服务旧式浏览器

ICO 文件其实有个目录结构可以打包不同分辨率的文件。我建议仅使用单张 32×32 的图片,除非你的图片不能很好的缩放到 16×16(比如变得更模糊)。在这种情况下,你可以要求你的设计师制作一个特殊版本的 Logo 以适应小像素网格。

不要自作聪明地用文件夹结构存放静态文件和 cache busters。网站 https://example.com 应该有一个 favicon 位于 https://example.com/favicon.ico。有些工具,例如 RSS 阅读器只会从服务器请求 /favicon.ico,而不会去其他地方请求了。

II. 具有明暗版本的单个 SVG 图标服务现代浏览器

SVG 是一种描述曲线而不是像素点的矢量格式。在大尺寸图片中,它比栅格图片更高效。在本文写作时,有 72% 的浏览器支持 SVG 格式。

你的 HTML 页面 <head> 中应该有个 <link> 标签,标签的属性是 rel="icon"type="image/svg+xml"href 指向 SVG 文件的链接。

SVG 是一种可以包含 <style> 标签来描述 CSS 的 XML 格式。和任何的 CSS 一样,它可以包含媒体查询,比如 @media (prefers-color-scheme: dark)。这样允许你使用同个图标在浅色和深色系统主题之间切换

III. 180×180 PNG 图片服务 Apple 设备

Apple touch icon 是一个 Apple 设备会在你添加网页到 iPhone 或 iPad 屏幕快捷方式时使用的图片。你的 HTML 页面 head 中应该有个<link rel="apple-touch-icon" href="apple-touch-icon.png> 标签。

iPad 自 iOS 8 之后要求 180×180 的分辨率。其他设备会对图片进行缩放,但如果我们提供的质量够高的源文件,缩放便不会对终端用户造成伤害(后面我会再讲)。

小笔记:如果你添加为 Apple touch icon 添加 20px 的 padding 和添加背景色,它观感会更好。你可以使用任何图片编辑器做到这点。

IV. 192×192 和 512×512 的 PNG 图片在 Web app manifest 中服务 Android 设备

  • Web app manifest 是一个 JSON 文件,其中包含浏览器将你的网站安装为系统应用的所有细节。该格式最初来自 Google 的 PWA 计划。
  • 你的 HTML 页面应该有个 <link rel="manifest" href="path.webmanifest"> 标签链接到 manifest 文件。
  • Manifest 应该有个 icon 字段链接到两个图标。192×192显示在屏幕上,512×512将作为PWA加载时的界面使用。
{
  "icons": [
    { "src": "/192.png", "type": "image/png", "sizes": "192x192" },
    { "src": "/512.png", "type": "image/png", "sizes": "512x512" }
  ]
}

我们是不是忘了什么?

当然,favicon 还有更多的类型,其中一些相当隐晦,让我们来看看我们的设置如何取代它们。也许是时候向一些不太成功的格式说再见了。

Windows Tile Icon

Microsoft Edge 曾经支持一种特殊的图标格式,用于将网站固定到开始菜单时使用。对于最近版本的 Windows 已经不再需要这样做了。

Safari Pinned Icon

Safari 曾经对 pinned tab 显示的图标有一个独立于 favicon 的要求。但是,自从 Safari 12 之后,我们可以在 pinned tab 上使用一般的 favicon。即便是 apple.com 也不再使用 mask-icon 了。

rel=”shortcut”

许多(过时的)教程会像这样子在 HTML 中引入 favicon.ico

<link rel="shortcut icon" href="/favicon.ico">

请注意,shortcut 不是,出来不是有效的 link relation。读 Mathias Bynens 在十年前的这篇文章,它向我们解释了为什么不需要 shoercut,只要使用 rel="icon" 就够了。

Yandex Tableau

Yandex 浏览器是俄罗斯最大的搜索引擎开发的基于 Chromium 的浏览器,它拥有 20% 的市场份额。它有一个很好的功能,允许网站通过 yandex-tableau-widget 链接特殊的 JSON 表单在主屏幕显示实时数据。然而,事实证明,这个功能并不是很受欢迎,现在 Yandex 已经从其网站上删除了它的技术文档。常规的图标表单也能正常工作。

Opera Coast

Opera Coast 是 iOS 上的实验性浏览器,曾经需要一个特殊的 228×228 的图标。这个浏览器已经于 2017 年从 App Store 上下架,所以我怀疑它是否能在从那之后的多次 iOS 更新中幸存下来。

现在,我们已经向这些逝去的同志挥手告别了,让我们来看看如何为那些健在的同志制作一套终极的 favicon 集。

如何打造我们的终极 favicon 集

以下是如何通过六个快速的步骤创建我们终极的极简 favicon 集。开始这些所需要的东西只有你想用来作为 logo 的 SVG 文件。

步骤1 准备 SVG

确保你的 SVG 图像是正方形,用图片浏览器打开你的源文件检查图像的长宽。SVG 的大小可以轻易地通过 SVG 编辑器调整。在 [Inkscape] 中,你可以在文件 → 文档属性中修改文件大小,可以在对象 → 对齐与分散中使 logo 居中放置。

icon.svg 保存你的文件。现在让我们来折腾一下我们的 SVG,让它更好地适应现代的系统主题。问一下你的设计师,在深色主题下颜色要如何反转(如果是黑白色的 Logo,你只需要把黑色改成白色)。

现在用文本编辑器打开你的 SVG 文件。找到暗色的或者没有 fill<path>。添加在主题变化时触发的 CSS 媒体查询并且修改 fill 为你想要的颜色:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
  <style>
    @media (prefers-color-scheme: dark) {
    .a { fill: #f0f0f0 }
    }
  </style>
  <path class="a" fill="#0f0f0f" d="…" />
</svg>

步骤2 创建 ICO 文件

在栅格图像编辑器中打开你的 SVG 文件。我推荐使用 GIMP;它免费开源且支持多平台。

在导入时将 SVG 渲染为光栅图像。设置宽度和高度为 32px。将文件导出为 favicon.ico,导出的图标细节选择 32bpp,8 位 alpha,无调色板选项。

如果你没有 GIMP 的话可以安装 InkscapeImageMagick,然后在终端里将 SVG 转为 ico:

inkscape ./icon.svg --export-width=32 --export-filename="./tmp.png"
# In Windows call `magick convert ./tmp.png ./favicon.ico`
convert ./tmp.png ./favicon.ico
rm ./tmp.png

将图片缩放到 16×16 并检查图标是否清晰。如果变得太模糊,最好是去找你的设计师制作一个微缩版本的 logo。

将另外的 16×16 版本包含进图标里:

  1. 打开 32×32 的 favicon.ico
  2. 创建一个 16×16 的新图层。
  3. 将 16×16 版本的图标放到图层里面。
  4. 导出文件。GIMP会保存每个大小布局并作为一个单独的图标输出。

或者你可以通过 ImageMagick 做一样的事情:

convert ./icon32.png ./icon16.png ./favicon.ico

步骤3 创建 PNG 图像

再一次在栅格图像编辑器中打开你的 SVG 原文件,并且创建一个 512×512 的图片并导出为 icon-512.png。再将图片缩放到 192×192 并导出为 icon-192.png。最后将图片本身缩放到 140×140 并将画布设置为 180×180,将它导出为 apple-touch-icon.png

或者你可以用 Inkscape 做一样的事情:

inkscape ./icon.svg --export-width=512 --export-filename="./icon-512.png"
inkscape ./icon.svg --export-width=192 --export-filename="./icon-192.png"

步骤4 优化 PNG 和 SVG

优化 SVG 的最好工具是 SVGO。使用方法:

npx svgo --multipass icon.svg

Squoosh 是一个强大的栅格图片网页优化工具。

  1. 在 Squoosh 中打开你的 icon-512.png
  2. 将压缩设置修改为 OxiPNG
  3. 启用 “Reduce palette”
  4. 设置 64 色。
  5. 通过移动滑块对比转换前/后的效果。如果看到前后肉眼可见的差别时便提高颜色数量以到看不出差别。
  6. 保存文件。

icon-192.pngapple-touch-icon.png重复以上步骤。

步骤5 添加图标到 HTML

你需要将 favicon.icoapple-touch-icon.png 用 link 添加到你的 HTML 中。

静态 HTML:

<title>My website</title>
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">

但是,我们更推荐使用 bundler 生成 cache busters(将文件的 hash 包含在名称中作为指纹)。如果你使用 Webpack 和 [html-webpack-plugin]:

  1. 创建 index.html 模板
  2. 添加模板到插件的设置:
new HtmlWebpackPlugin({ template: "./view/index.html" });
  1. 用 links 在 HTML 模板中声明(例子使用 ERB 来引用文件,但你可以使用你选择的模板语言):
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>My website</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="icon" href="/favicon.ico">
    <link rel="icon" type="image/svg+xml" href="<%=
      require('./icon.svg').default
    %>">
    <link rel="apple-touch-icon" href="<%=
      require('./apple-touch-icon.png').default
    %>"
   >
  </head>
  <body></body>
</html>
  1. 使用 copy-webpack-plugin 来复制 favicon 而不添加 hash 到它的名称上。

免费建议:独立的图标用于测试环境

使用不同的 favicon 是个区分生产环境和测试环境的好方法。我发现在测试环境中使用替代图标是避免造成高昂代价混乱的一个超级有效的方法。

创建一个相同现状但是反转了颜色(或者用任何你能区分的方法)的 logo,将其命名为 favicon-dev.ico。对 SVG 文件也做同样的处理,创建并命名为 icon-dev.svg

使用 process.env.NODE_ENV === 'production' 条件判断替代模板中的图标:

  <!doctype html>
  <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>My website</title>
      <meta name="viewport" content="width=device-width,initial-scale=1">
-     <link rel="icon" href="/favicon.ico">
+     <link rel="icon" href="<%=
+       process.env.NODE_ENV === 'production'
+         ? '/favicon.ico'
+         : require('./favicon-dev.ico').default
+     %>">
      <link rel="icon" type="image/svg+xml" href="<%=
-       require('./icon.svg').default
+       process.env.NODE_ENV === 'production'
+         ? require('./icon.svg').default
+         : require('./icon-dev.svg').default
      %>">
      <link rel="apple-touch-icon" href="<%=
        require('./apple-touch-icon.png').default
      %>">
    </head>
    <body></body>
  </html>

步骤6 创建一个 web app manifest

对于静态 HTML,创建个 JSON 文件并命名为 manifest.webmanifest 即可:

{
  "name": "My website",
  "icons": [
    { "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
    { "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" }
  ]
}

链接到 HTML 中:

  <title>My website</title>
+ <link rel="manifest" href="/manifest.webmanifest">
  <link rel="icon" href="/favicon.ico">
  <link rel="icon" href="/icon.svg" type="image/svg+xml">
  <link rel="apple-touch-icon" href="/apple-touch-icon.png">

使用 Webpack 的话,你可以使用 webpack-pwa-manifest 插件:

plugins: [
  …,
  new WebpackPwaManifest({
    name: 'My website',
    icons: [
      { src: resolve('./icon-192.png'), sizes: '192x192' },
      { src: resolve('./icon512.png'), sizes: '512x512 }
    ]
  })
]

谢谢你阅读这篇文章!如你所见,使用现代的 web 标准后,创建一个终极 favicon 集的任务也变得相当直接了。即使你跟着上面的步骤动手制作也不会花多少时间,但如果有个自动化工具会让这件事更加 amazing!如果你愿意制作这样子的工具的话请通过 Twitter 与我联系;我会非常高兴帮助你!

2021-05-26:改正了文章中的一些 typo。

Thumbnail matrial from Storyset

评论

您所在的地区可能无法访问 Disqus 评论系统,请切换网络环境再尝试。