logo

2024728

PWAの見栄えをそこそこ良くする設定まとめ【令和最新版】

PWA (Progressive Web App) が普及し始めてからしばらく経ちました。Android が積極的に対応を進めてきましたが、最近は iOS でもそれなりに対応が進みました。久しぶりに PWA と向き合い、今時のスマホ向けに見栄えを良くするための設定をまとめました。

やること

  • アイコン
  • ステータスバーの色の設定
  • iPhone の画面への対応

通知や Service Worker 等の機能面はこの記事のスコープ外とします。

デモ

PWA デモ

リンク先のページで実際にこの記事で試した内容を試せます。

アイコン

これは数年前から特に変わりないと思いますが、改めて作り直しました。

アイコン画像の作成

Apple のベストプラクティス を軽く見ておくといいかもしれません。私は Apple Design Resources のページにある Production Templates を使用してアイコンを作りました(と言っても背景の上にシンボルを載せただけですが……)。だいたいどの範囲にロゴやシンボルを収めればいいのかがわかるので便利です。

photoshop

1024px で作成し、必要なサイズのアイコン画像を書き出せば良いでしょう。

manifest.json の icons プロパティ

下記の内容を検証しました。

{
  "icons": [
    {
      "purpose": "any",
      "src": "./img/icons/192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "purpose": "any",
      "src": "./img/icons/512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "purpose": "maskable",
      "src": "./img/icons/maskable-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "purpose": "maskable",
      "src": "./img/icons/maskable-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

画像サイズは Chromium で最低限必要な 192x192512x512 を用意しました。1

Purpose any デフォルトで使用されるアイコンです。iOS はこれを使うみたいです。maskable は画像からシステムが様々な形にマスクする(切り抜く)時に使われます。Android のアダプティブアイコンがその例で、サークルやスクワークルに切り抜けることは Android ユーザーにはお馴染みかと思います。

maskable に指定する画像は any に指定する画像よりもアイコンに描かれるロゴやシンボルを小さめにしておく必要があります。具体的には、画像の(基本は正方形かと思いますが)短辺の80%の直径の円(= 安全領域)の中に描かれないといけません。

safe zone

https://maskable.app/ ではアイコンがどのように maskable として使用されるのかプレビューできます。

maskable.app

Puepose には他に monochrome があります。これに指定された画像は色情報が破棄され、アルファデータ(透明度)だけが使用されます。主に塗りつぶしのマスクの用途です。

https://monochrome.fyi/ ではアイコンがどのように monochrome として使用されるのかプレビューできます。

monochrome.fyi

Material You で monochrome アイコンを使っているのか気になりましたが、未実装のようです。2
iOS 18 のアイコンも Material You と同じようにアイコンの色をテーマに合わせられるようになるみたいなので、PWA にも適用されるのかが気になります。

Android 版 Chrome でインストールした PWA では通知バーのアイコンに使われるのかもと思って試してみましたが、ServiceWorkerRegistration.showNotification()badge オプションで渡さないと通知バーのアイコンとして表示されませんでした。3

そのため、現時点で manifest.json の monochrome アイコンを使用する実装を見つけることはできませんでした。

ステータスバーの色の設定

時刻や Wi-Fi のアイコンが並んでいるステータスバーが真っ白や真っ黒ではなく、アプリと一体になっているとネイティブアプリ感が増します。manifest.json の theme_color で設定することが多かったと思いますが、manifest では動的に変えることができないので、現時点では <meta> タグで記述する方が良さそうです。

下記はライトモードとダークモードで theme-color を出し分ける書き方です。複数の theme-color に未対応のブラウザもあるので、フォールバックさせたい方を最初に持ってくると良いです。

<meta name="theme-color" content="#E5E5E5" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#171717" media="(prefers-color-scheme: dark)" />

android chrome light

Android 版 Chrome でページをタブで開いているとき(PWA でないとき)、かつ、ダークモード時に theme-color が適用されないのは仕様ですので覚えておきましょう。

android chrome dark

↑ Android 版 Chrome では UI のアドレスバーの色が theme-color にならない

Next.js の `next/head` 内に記述する場合

同じ name 属性のタグがあると最後のやつだけが生き残って他のタグは HTML に出力されないので、key を使って別物だと認識させましょう。key の値はなんでもいいです。

<meta name="theme-color" content="#E5E5E5" media="(prefers-color-scheme: light)" key="theme-color-light" />
<meta name="theme-color" content="#171717" media="(prefers-color-scheme: dark)" key="theme-color-dark" />

iOS

iOS の PWA では Apple 特有の <meta> タグで black-translucent を指定して、ステータスバーの背景を透過させるとネイティブアプリ感が高まっておすすめです。apple-mobile-web-app-status-bar-style を使うためには apple-mobile-web-app-capable も指定する必要があります。

<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />

ios pwa

↑ PWA として動作しているとき

ただし PWA として動作していないとき(= ホーム画面に追加されていないとき、Safari のタブとして開いているとき)は theme-color が使用されます。

ios safari

↑ Safari のタブとして開いているとき

iPhone の画面への対応

今回重要なのは viewport-fit=cover の部分で、これをつけることでステータスバーやホームバーの後ろに Web サイトをレンダリングできるようになります。

<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover,user-scalable=no" />

viewport-fit=cover

その代わり、画面の上下左右に位置する HTML 要素にはパディングをつけてあげる必要があります。安全領域(safe area)外の上下左右の大きさは env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left) で取得できます。

例えば、画面の上部に .header があったとして従来は以下のように指定していたとしたら

.header {
  padding-top: 10px;
}

次のように safe-area-inset-top の分だけ足してあげれば良いです。安全領域がない端末ではこの値は 0px なので、端末によって出し分けたりする必要はありません。

.header {
  padding-top: calc(env(safe-area-inset-top) + 10px);
}

ios safearea portrait

ios safearea landscape

参考文献

Footnotes

  1. https://web.dev/articles/add-manifest?hl=ja#icons

  2. https://stackoverflow.com/questions/74620798/material-you-icon-on-pwa
    https://issues.chromium.org/issues/40277264

  3. Android 版 Firefox では badge オプションをつけても無視されました。