Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails以外の開発一般

2021年のファビコンを極める: 本当に必要なファイルはほぼ6つ(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。

2021年のファビコンを極める: 本当に必要なファイルはほぼ6つ(翻訳)

はじめに

モダンブラウザで使われるファビコンの作り方を見直して、今こそアイコン生成であくせくするのを終わりにしましょう。昨今のフロントエンド開発者は、ブラウザタブやらタッチ画面やらにWebサイトの小さなロゴを表示する、ただそれだけのためだけに静的なPNGファイルを20個以上扱わなければなりません。よりスマートな方法で、現代のニーズに合う最小限のアイコンセットを使う方法を紹介します。

ファビコンは見かけよりもずっと幅広く奥深いトピックで、実は誰もがファビコンについてしっかり学びたいと思っていることもわかってきました。本記事の内容をわずか2行のスニペットに凝縮したものも紹介していますので、今ファビコンで苦しんでいる方は(正確な使い方をご存知なら)そちらをお使いいただけますが、そこをぐっとこらえて記事を最後までお読みいただくことをおすすめいたします。

忙しい人向け: ウルトラショート版解説

苦労してアイコンを10個以上用意しなくても、以下のようにたった5個のアイコンとJSONファイル1個があればできます。

ブラウザ用HTMLに以下のように書きます。

<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アプリのマニフェストJSONファイルに以下のように書きます。

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

たったこれだけで完了です。私がこの方法にたどり着くまでの経緯や妥協しなければならなかった点、および手順を追ってゼロから行う方法を学びたい方は、ここから先へお進みください。

完全版解説

“完璧の域に達するのは、付け足すものがなくなったときではなく、削るところがなくなったときである。”
アントワーヌ・ド・サン=テグジュペリ『Airman’s Odyssey』(日本語未訳)

ファビコン(favicon: favorite iconの略)という概念が登場したのは2000年代初頭のことです。ブラウザのタブバーにいつも可愛らしい画像がちっちゃく表示されて、現在どのWebサイトを開いているかを知らせてくれるのを誰もが目にしています。ユーザーはWebサイトにファビコンがあるのが普通だと考えているものです。一見ささいなことに思えますが、ファビコンは大事だと考える人は世の中にたくさんいるのです。

Appleはこれまでずっと、自社以外のアイコンが表示されるのは審美的によろしくないとばかりにSafariのファビコン表示をぞんざいに扱っていましたが、そのAppleですら今や自社の全デバイスでファビコンを正しく表示するようになったのです。


一般に公開するWebサイトを運営するなら、ファビコンをちゃんと用意しなければなりません。ユーザーから見えるアイコンはたった1個ですが、実際にはいくつものアイコンが必要とされています。


そういうわけで、種類が増え続ける画面やデバイスに対応するアイコンファイルを生成するために、ファビコン生成ツールを用いるのが一般的です。まともな人ならファビコンごときに数時間もかけたくないでしょう。私たちはWebサイトを作ろうとしているのであって、ブラウザベンダーを喜ばせるために仕事をしているのではありません。

有名なファビコン生成サイトで生成した大量のファビコンファイル

私はNanoIDの作者として、また「ミニマルなオープンソース」の提唱者として、物事をやや別の側面から考えるところがあります。Webサイトで最も効率のよいアイコンセットとはどんなものでしょうか?時代遅れになったファイルフォーマットはどれでしょうか?少々の妥協と引き換えに置き換えても大丈夫なアイコンはどれでしょうか?

そこで私は、どんな場合でもあらゆるブラウザで正しく表示される最小限のファビコンリストを作ることにしました。たまに表示がわずかにおかしくなることがあったとしても表示は引き続き可能な、そういうファビコンリストです。

究極のファビコンリストをセットアップする

私は、大きさの異なる画像ファイルを大量に作るのをやめて、SVG画像とブラウザの画像縮小機能を頼りにすることに決めました。そんなことをしたらパフォーマンスが落ちるのではとご心配の方へ: ここで皆さんの誤解を解いておきたいと思います。

  • ブラウザはファビコンをバックグラウンドでダウンロードします。したがって、ファビコン画像はWebサイトのパフォーマンスに影響しません。
  • SVGフォーマットは、元がビットマップでない画像のサイズを縮小するのに適しています。「たいていの」ロゴはPNGよりもSVGの方がずっとサイズが小さくなります。
  • PNG画像3つという最小限のファイルセットがあれば、高度なツールを用いて画像サイズを最適化できます。これにより、ネット接続が無制限プランでないネットユーザーの問題を解決できます。

以下に紹介するのが、私がこれまで研鑽と実践を重ねてきた最小限のアイコンセットです。メジャーなブラウザやデバイスであれば、新旧を問わず正しく表示できるはずです。

1. favicon.ico(レガシーブラウザ用)

ICOファイルは一見ファイルのようですが、実際にはディレクトリ構造があり、解像度の異なるさまざまなファイルをその中に保存できます。ICOファイルのサイズですが、特別な理由がない限り、32×32画像1個だけにしておくことをおすすめします。たとえば16×16表示のアイコンがぼやけてしまうといった問題が生じたら、改めてそうした小さいサイズで正しく表示できる特別なロゴをデザイナーに依頼しましょう。

このとき、ICOファイルをわざわざ静的アセット用ディレクトリに置いたり、キャッシュバスターを使ったりするなどの小細工を行わないこと。https://example.comというWebサイトであれば、https://example.com/favicon.icoに置いてください。RSSリーダーなど一部のツールはサーバーの/favicon.icoにしかリクエストを送信せず、それ以外の場所をわざわざ探そうとしません。

2. ライト/ダークモード対応のSVGアイコン(モダンブラウザ用)

SVGファイルは、ピクセルではなく曲線を記述するベクタフォーマットです。SVGはサイズが大きくなるほど、いわゆるラスター画像よりも効率が高まります。本記事執筆時点では、全ブラウザの72%がSVGアイコンをサポートしています(caniuse.com)。

この場合、HTMLページの<head>セクション内に<link>タグを追加し、その<link>タグにrel="icon"属性とtype="image/svg+xml"属性を指定したうえで、SVGファイルへのリンクをhref属性で指定する必要があります。

SVGファイルはXMLフォーマットになっていて、その中にCSS記述用の<style>タグが含まれています。普通のCSSと同様、ここにも@media (prefers-color-scheme: dark)のようなメディアクエリを書けます。こうすることで、同じアイコンをダークテーマとライトテーマに応じて切り替えられます(参考:『prefers-color-scheme in SVG favicons for dark mode icons』)。

3. 180×180 PNG画像(Appleデバイス用)

Appleの「タッチアイコン(touch icon)」は、iPhoneやiPadのホーム画面上にWebページを追加したときに表示される、Apple製デバイス用の画像です。この場合、HTMLの<head>セクション内に<link rel="apple-touch-icon" href="apple-touch-icon.png">というタグを置く必要があります。

この画像は、iOS 8以降のiPadでは180×180の解像度が必要ですが、その他のデバイスでは画像が縮小されます。ただし、縮小に耐える十分な品質の画像を使っていれば、画像が縮小されてもユーザーには影響しません(後述)。

メモ: Appleのタッチアイコン画像の周囲にパディングを20px確保し、背景にも色を付けておけば、アイコン表示がより整います。タッチアイコンはどんな画像編集ソフトでも問題なく扱えます。

4. Webアプリマニフェスト + 192×192 PNGアイコン + 512×512 PNGアイコン(Android用)

  • WebアプリマニフェストはJSONファイルで、Webサイトをシステムアプリケーションとしてインストールするときにブラウザが用いる詳細情報がすべて保存されます。このフォーマットの由来は、GoogleのPWA(Progressive Web Application)イニシアティブです。
  • これを用いるには、HTMLファイルに<link rel="manifest" href="webmanifestへのパス">タグを追加して、マニフェストファイルへのリンクを記述する必要があります。
  • マニフェストファイルでは2つのアイコンにリンクするiconsフィールドが必要です。192×192のアイコンはホーム画面用、512×512のアイコンはPWA読み込み中のスプラッシュ画面用です。
{
  "icons": [
    { "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
    { "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" }
  ]
}

何か忘れてない?

はい、もちろんこれ以外にもファビコン関連のファイルはたくさんありますし、中にはろくに知られていないものもあります。日の目を見なかったファビコンフォーマットたちにそろそろさよならを言うときが来たようです。

Windowsのタイルアイコン

Microsoft Edgeではかつて、タイルアイコンという特殊なアイコンフォーマットがサポートされていたことがあり、Webサイトをスタートメニューに固定するのに用いられていました。しかし最近のWindowsではもはやこのアイコンが必須ではなくなりました。

Safariのタブ固定時アイコン

Safariでも、タブ固定時に表示するアイコン(pinned icon)が別途必要とされていました。しかしSafari 12以降は普通のファビコンをタブ固定時アイコンに使えるようになりました。今や本家apple.comでもmask-iconは使われていません。

rel="shortcut"

世の中には、未だに「HTMLにfavicon.icoを含めるときは以下のようにしましょう」という化石のような知識を教えるチュートリアルが山ほどあります。

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

ぜひともご注意ください。このshortcutというリンク種別は今やまったく無効です。詳しくはMathias Bynensが10年も前に書いた素晴らしい記事『rel=”shortcut icon” considered harmful · Mathias Bynens』には、shortcutが完全に不要である理由と、rel="icon"で十分な理由が説明されています。

icon より以前はリンク種別 shortcut がよく使用されていましたが、これは非準拠で無視されますのでウェブ作者は今後使用してはいけません。
リンク種別 - HTML: HyperText Markup Language | MDNより

Yandexブラウザのタブローウィジェット

Yandexは、ロシア最大の検索エンジン会社によるChromiumベースのブラウザで、ロシアでは20%のシェアがあります。Yandexには「タブロー(Tableau: 情景)」というなかなかよい機能があり、yandex-tableau-widgetで特殊なJSONマニフェストを提供すると、そのWebサイトをホーム画面上のライブウィジェットとして表示できます。しかしこの機能はあまり受けていないことがわかってきたため、Yandexは自社Webサイトからタブローの技術ドキュメントを削除しました。現在は普通のアイコンマニフェストも問題なく使えます。

Opera Coastブラウザ

Opera CoastというiOS向けの実験的ブラウザでは、228×228という特殊なサイズのアイコンが必要でした。このブラウザは2017年にApp Storeから姿を消しています。その後に何度もアップデートされたiOSでこのブラウザが果たして動くかどうかも怪しいところです。

累々と横たわる戦友たちにこの辺で別れを告げることにして、今度は今も戦い続けているブラウザたちのために究極のファビコンセットの作り方を見ていくことにしましょう。

究極ファビコンセットの作り方

ここからは、究極のファビコンミニマムセットを6つの簡単なステップで手軽に作る方法をご紹介します。ファビコンに使いたいSVGファイルが1個あれば、すぐ始められます。

ステップ1: SVGファイルを準備する

SVG画像は必ず「正方形」であることを確認してください。画像をシステムのビューアで開いて、高さと幅が正方形になっているかどうかを確かめておきましょう。SVGエディタなら簡単に調整できます。InkscapeからダウンロードできるInkscapeアプリでSVGファイルを開き、「ファイル > ドキュメントのプロパティ」メニューでドキュメントのサイズを変更し、「オブジェクト > 整列と配置」メニューでロゴを中央揃えにできます。

このファイルをicon.svgという名前で保存します。続いて、このSVGファイルに手を加えて最新のシステム「テーマ」に対応させましょう。ダークテーマで色をどのような形で反転すべきかについて、デザイナーに問い合わせておいてください(白黒のロゴなら単純に白黒反転するだけでよいでしょう)。

反転方法が決まったら、いよいよSVGファイルを「テキストエディタ」で開きます。fillがダークテーマ用になっている<path>タグ(またはfillがない<path>タグ)を探します。システムテーマ変更時にトリガーするCSSメディアクエリを<style>タグに追加し、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 fill="#0f0f0f" d="..." />
+   <path class="a" fill="#0f0f0f" d="..." />
  </svg>

ステップ2: ICOファイルを作成する

このicon.svgファイルを、ラスター画像エディタで開きます(個人的には無料かつマルチプラットフォームのGIMPがおすすめです)。

レンダリング方法をSVGからラスターに変更し、幅と高さを32ピクセルに設定したら、favicon.icoというファイル名でエクスポートします。このときに「32 bpp, 8-bit alpha, no palette」を指定します。

GIMPをお持ちでない場合は、以下のようにターミナルでInkscapeImageMagickを使えばSVGをICOファイルに変換できます。

inkscape ./icon.svg --export-width=32 --export-filename="./tmp.png"
# Windowsの場合以下を`magick convert ./tmp.png ./favicon.ico`にする
convert ./tmp.png ./favicon.ico
rm ./tmp.png

訳注

ImageMagickのバージョンの注意点について、「convertコマンドの使い方: UNIX/Linuxの部屋」より引用します。

●ImageMagick バージョン7 以降の注意点
ImageMagick バージョン7 より、convert 等のコマンドがなくなり magick コマンドに変更されている。Windows で関係ない convert コマンドが存在し、混乱を招くため。2017年9月現在、FreeBSD では ImageMagick がバージョン6、ImageMagic7 がバージョン7 として ports/packages が用意されている。
同記事より

次に変換で作成したfavicon.icoファイルの画像サイズを16×16に縮小して表示を確かめます。もし画像がぼやけてしまった場合は、デザイナーに依頼して小さな表示に最適化したロゴも作ってもらいます。

favicon.icoに16×16版のアイコンも含めるには次のようにします。

  1. 32×32のfavicon.icoファイルを開く。
  2. 16×16版アイコン用のレイヤを1つ追加する。
  3. このレイヤに16×16版のアイコンを貼り付ける。
  4. ファイルにエクスポートする(GIMPは、異なるICONバージョンを個別のレイヤに保存します)。

以下のようにImageMagickのコマンドを用いても同じ結果が得られます。

convert ./icon-32.png ./icon-16.png ./favicon.ico

ステップ3: PNG画像を作成する

元のSVGファイルを再びラスター画像エディタで開いて、512×512の画像を作成し、icon-512.pngというファイル名でエクスポートします。

次に同じ画像のサイズを192×192に変換したものも作成し、icon-192.pngというファイル名でエクスポートします。

最後にその画像自体のサイズを140×140に変換し、さらにキャンバスのサイズを180×180にしたうえで、apple-touch-icon.pngというファイル名でエクスポートします。

最初の2つについては、以下のように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は、ラスター画像の最適化に適しているWebアプリです。

  1. Sqooshサイトにicon-512.pngをアップロードまたはドロップします。
  2. 圧縮設定をOxiPNGに変更します。
  3. “Reduce palette”を有効にします。
  4. その下の”colors”を64に設定します。
  5. ブラウザの真ん中にあるスライダーを左右に動かして変更前/変更後を比較します。色味が変わっていたら、”colors”の色数を増やします。
  6. ファイルを保存します。

icon-192.pngapple-touch-icon.pngについても上のステップを繰り返します。

ステップ5: HTMLにアイコンを追加する

favicon.icoへのリンクとapple-touch-icon.pngへのリンクを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">

しかし、このときに何らかのバンドラー機構を用いて「キャッシュバスター」を生成しておくことをおすすめします(つまりファイル名に846acd9bc30aのようなハッシュを含めてフィンガープリントとして使います)。Webpackでhtml-webpack-pluginを使っている場合は、以下の手順でできます。

  • index.htmlテンプレートを作成します。
  • テンプレートに以下のプラグインオプションを追加します。
new HtmlWebpackPlugin({ template: "./view/index.html" });
  • リンクを含む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>
  • favicon.icoをコピーするときは、copy-webpack-pluginを使って、ファイル名にハッシュを追加「せずに」行います。

無料の小技: stagingで別のアイコンを使う

ファビコンは、環境がproductionかstagingかを区別するにも便利です。staging環境のアイコンを別のものに変えておくと、productionとstagingを取り違えて痛い目に遭わないための対策として非常に有効であることに気づきました。

ICOファイルの色だけを反転させたfavicon-dev.icoファイルを作成します(ひと目で区別が付けば他の方法でも構いません)。同様にSVGファイルについても色を反転させたicon-dev.svgファイルを作成します。

そして、process.env.NODE_ENV === 'production'条件に応じてHTMLテンプレート内のアイコンを差し替えます。

  <!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アプリのmanifestを作成する

静的HTMLの場合は、以下のmanifest.webmanifestというJSONファイル名を作成します。

{
  "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('./icon-512.png'), sizes: '512x512 }
      ]
    })
  ]

お読みいただいた皆さんに感謝です。ご覧いただいたように、モダンなWeb標準を活用したことで、究極のファビコンセットをとても素直に作成できるようになりました。紹介した手順は手動で進めてもさほど手間ではありませんが、同じことを自動化ツールでできればさらに便利でしょう。我こそはとお思いの方がいらっしゃいましたら、Twitterの@sitnikcodeまでお知らせいただければ喜んでお手伝いいたします。

本記事の翻訳や転載についてのご相談は、まずメールにてお願いします。

関連記事

HotwireはRailsを「ゼロJavaScript」でリアクティブにできるか?前編(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。