ウェブセキュリティ

ウェブセキュリティ
=========

ウェブサイトや公開ウェブアプリケーションが安全であることを保証するのは重要なことです。コードの中の単純なバグが、個人情報の漏洩という結果を招くことがありますし、データを盗む方法を見つけようとしている悪い輩があちこちにいます。以下に紹介するセキュリティ方面の記事では、コードの安全性を確保する際に助けとなる情報を提供しています。

コンテンツセキュリティ
-----------

コンテンツセキュリティポリシー (CSP)

**コンテンツセキュリティポリシー** (CSP) は、クロスサイトスクリプティング (XSS) やデータインジェクション攻撃などのような、特定の種類の攻撃を検知し、影響を軽減するために追加できるセキュリティレイヤーです。これらの攻撃はデータの窃取からサイトの改ざん、マルウェアの拡散に至るまで、様々な目的に用いられます。

コネクションセキュリティ
------------

Transport layer security (TLS)

Transport Layer Security (TLS) プロトコルは、ネットワークで結ばれた 2 つのアプリケーションや端末が、私的にかつ強固に情報交換するための標準です。TLS を使用するアプリケーションは、セキュリティ引数を選択することができ、これは、データのセキュリティと信頼性に大きな影響を与える可能性があります。この記事では、TLS の概要と、コンテンツを保護するために必要な決定の種類について説明します。

HTTPS

**HTTPS** (***HyperText Transfer Protocol Secure***) は、HTTP プロトコルの暗号化バージョンです。SSL または TLS を使用して、クライアントとサーバー間のすべての通信を暗号化します。この安全な接続により、クライアントは意図したサーバーに接続されていることを確認し、機密データを交換することができます。

HTTP Strict-Transport-Security

`Strict-Transport-Security:` は HTTP のヘッダーで、ウェブサイトを HTTPS を使用してのみアクセスできるようにするものです。

電子証明書の透明性

**電子証明書の透明性**は、証明書の誤発行を防止し、監視するために設計されたオープンなフレームワークです。新しく発行された証明書は、公開されている、多くの場合独立した CT ログに「記録」され、発行された TLS 証明書の追加のみの暗号的に保証された記録を維持します。

混在コンテンツ

HTTPS のページの中に通常の平文の HTTP で送られてくるコンテンツが含まれている場合、**混在コンテンツ**と呼ばれます。このようなページは部分的にしか暗号化されておらず、盗聴者や中間者攻撃者が暗号化されていないコンテンツにアクセスできてしまいます。

混在コンテンツでブロックされるウェブサイトを修正するには

ウェブサイトを HTTPS で配信している場合、ページ上にある 能動的な混在コンテンツはすべて既定でブロックされます。結果として、ユーザーからはそのウェブサイトが壊れているように見えるかもしれません (iframe やプラグインが読み込まれないなど)。一方、受動的な混在コンテンツは既定で表示されますが、このようなコンテンツをブロックするようにユーザーが設定することも可能です。このページでは、ウェブ開発者として知っておくべきことを説明します。

安全なコンテキスト

**安全なコンテキスト (Secure Context)** とは、(HTTPS/TLS を介して) コンテンツが安全に配信され、安全**ではない**コンテキストとの通信の可能性が限られているという合理的な確信がある `Window`、または `Worker` のことです。多くの Web API が安全なコンテキストでのみ利用可能です。安全なコンテキストの主目的は、中間者攻撃者が被害者に更なる危険にさらす可能性がある強力な API にアクセスするのを防ぐことにあります。

安全なコンテキストに制限されている機能

このリファレンスは、安全なコンテキストでのみ使用できるウェブプラットフォーム機能の一覧です。

脆弱な署名アルゴリズム

デジタル証明書の電子署名に用いられるハッシュアルゴリズムの強度は、証明書のセキュリティにおいて核心的な要素です。この記事では、脆弱になったため、可能であれば避けるものと知られている署名アルゴリズムについて、いくらかの情報を提供します。

301 および 302 レスポンスコードによるリダイレクト

執筆予定

データセキュリティ
---------

HTTP Cookie の使用

HTTP Cookie (ウェブ Cookie、ブラウザー Cookie) は、サーバーがユーザーのウェブブラウザーに送信する小さなデータであり、ブラウザーに保存されて次のリクエストと共に同じサーバーへ返送されます。一般的には、二つのリクエストが同じブラウザーから送信されたものであるかを知るために使用されます。例えば、ユーザーのログイン状態を維持することができます。

ローカルストレージ

`Window` オブジェクトの `Window.localStorage` プロパティは、サーバーがクライアントにセッションを通して存在するデータを格納する一つの手段です。

情報漏洩
----

Referer ヘッダーのプライバシーとセキュリティの考慮事項

HTTP の Referer ヘッダーにまつわるプライバシーとセキュリティのリスクがあります。この記事ではこれらを説明し、これらのリスクを回避するためのアドバイスを提案します。

Robots.txt

執筆予定

Site maps

執筆予定

完全性
---

同一オリジンポリシー

**同一オリジンポリシー**とは、あるオリジンから読み込まれた文書やスクリプトについて、そのリソースから他のオリジンのリソースにアクセスできないように制限するものです。同一オリジンポリシーはウェブのセキュリティにおける重要な仕組みであり、悪意ある行動を起こしかねないリソースの分離を目的としています。

サブリソース完全性

**サブリソース完全性** (Subresource Integrity) (SRI) は、(CDN などから) 取得したリソースが意図せず改ざんされていないかをブラウザーが検証するセキュリティ機能です。SRI を利用する際には、取得したリソースのハッシュ値と一致すべきハッシュ値を指定します。

HTTP の Access-Control-Allow-Origin

**`Access-Control-Allow-Origin`** レスポンスヘッダーは、指定されたオリジンからのリクエストを行うコードでレスポンスが共有できるかどうかを示します。

HTTP X-Content-Type-Options

**`X-Content-Type-Options`** は HTTP のレスポンスヘッダーで、`Content-Type` ヘッダーで示された MIME タイプを変更せずに従うべきであることを示すために、サーバーによって使用されるマーカーです。これにより、MIME タイプのスニッフィングを抑止することができます。すなわち、ウェブマスターが自分が何をしているかを分かっていると言う手段です。

クリックジャックからの保護
-------------

クリックジャックでは、ユーザーがだまされて、ユーザーが期待するもの以外のアクションを実行する UI 要素をクリックします。

HTTP X-Frame-Options

**`X-Frame-Options`** HTTP レスポンスヘッダーを使用して、ブラウザーが `<frame>`, `<iframe>`, `<embed>`, `<object>` でページをレンダリングできるかどうかを示すことができます。サイトはこれを使用してコンテンツが他のサイトに埋め込まれないようにすることで、クリックジャッキング攻撃を回避できます。

CSP: frame-ancestors

HTTP `Content-Security-Policy` (CSP) **`frame-ancestors`** ディレクティブは、 `<frame>`, `<iframe>`, `<object>`, `<embed>`, `<applet>` を使用して、ページを埋め込むことができる有効な親を指定します。

ユーザー情報セキュリティ
------------

安全でないパスワード

HTTP 経由でログインフォームを送信することは、ユーザのパスワードを抽出するために使用できる様々な攻撃があるため、特に危険です。ネットワーク盗聴者は、ネットワークを盗聴したり、転送中に提供されたページを変更したりすることで、ユーザのパスワードを盗むことができます。

プライバシーと :visited セレクター

2010 年頃までは、CSS `:visited` セレクターにより、ウェブサイトがユーザーの閲覧履歴を明らかにし、そのユーザーがどのサイトを訪問したかを把握することができました。この問題を軽減するために、ブラウザーは訪問したリンクから取得できる情報量を制限しています。

セキュリティに関する用語集の用語
----------------

* Block cipher mode of operation
* Certificate authority
* Challenge-response authentication
* Cipher
* Cipher suite
* Ciphertext
* CORS
* CORS-safelisted request header
* CORS-safelisted response header
* Cross-site scripting
* Cryptanalysis
* Cryptographic hash function
* Cryptography
* CSP
* CSRF
* Decryption
* Digital certificate
* DTLS
* Encryption
* Forbidden header name
* Forbidden response header name
* Hash
* HMAC
* HPKP
* HSTS
* HTTPS
* Key
* MitM
* OWASP
* Preflight request
* Public-key cryptography
* Reporting directive
* Robots.txt
* Same-origin policy
* Session hijacking (en-US)
* SQL injection
* Symmetric-key cryptography
* TOFU

* TLS
関連情報
----

* ブログ
* @mozsec (Twitter)


オープンウェブ技術のデモ

オープンウェブ技術のデモ
============

Mozilla は多種多様なオープンウェブ技術に対応しており、使用を推奨しています。このページでは、これらの技術の興味深いデモンストレーションへのリンクを提供しています。

もしオープンウェブ技術の優れたデモンストレーションやアプリケーションをご存知でしたら、ここの適切な節にリンクを追加してください。

2D グラフィック
---------

### キャンバス

* Blob Sallad: an interactive blob using JavaScript and canvas (code demos)
* miniPaint: Image editor (source code)
* Zen Photon Garden (source code)
* Multi touch in canvas demo (source code)
### SVG

* Bubblemenu (visual effects and interaction)
* Blobular (interactive)
* Summer HTML image map creator (source code)
### Video

* Video 3D Animation "mozilla constantly evolving"
* Video 3D Animation "Floating Dance"
* Video 3D Animation "The Gravel Institute: Monopoly
3D グラフィック
---------

### WebGL

* Web Audio Fireworks
* Aquarium
* Dynamic cubemap
* Kai 'Opua (source code)
### バーチャルリアリティ

* The Polar Sea (source code)
* Sechelt fly-through (source code)
CSS
---

* CSS floating logo "mozilla"
* CSS Blockout
* Rubik's cube
* Loader with blend modes
* CSS-based single page application (source code)
### 座標変換

* Impress.js (source code)
* Flickr Polaroid Stack
ゲーム
---

* IoQuake3 (source code)
* Kai 'Opua (source code)
ウェブ API
-------

### 通知 API

* HTML Notifications (source code)
### ウェブオーディオ API

* Audio Context states demo
* Audio analyser - graphical visualization of an audio signal
* IIR filter node
* Multi track
* Stereo-panner-node
### ファイル API

* Slide My Text - presentation from plain text files
### ウェブワーカー

* Web Worker Fractals
* Photo editor
* Coral generator
* Raytracer
* Fibonacci


XSLT: 拡張可能なスタイルシートの言語変換

XSLT: 拡張可能なスタイルシートの言語変換
=======================

**XSLT/XPath リファレンス**: XSLT 要素, EXSLT 関数, XPath 関数, XPath 軸

1. **XSLT**
2. **EXSLT**
3. **XPath**
4. ガイド
    1. よくある XSLT のエラー
    2. PI 引数
    3. Gecko の XSLT/JavaScript インターフェイス
    4. XML を XSLT で変換
    5. Mozilla JavaScript インターフェイスからの XSLT の使用
5. XSLT Elements (en-US)
    1. `<xsl:apply-imports>`
    2. `<xsl:apply-templates>`
    3. `<xsl:attribute-set>`
    4. `<xsl:attribute>`
    5. `<xsl:call-template>`
    6. `<xsl:choose>`
    7. `<xsl:comment>`
    8. `<xsl:copy-of>`
    9. `<xsl:copy>`
    10. `<xsl:decimal-format>`
    11. `<xsl:element>`
    12. `<xsl:fallback>`
    13. `<xsl:for-each>`
    14. `<xsl:if>`
    15. `<xsl:import>`
    16. `<xsl:include>`
    17. `<xsl:key>`
    18. `<xsl:message>`
    19. `<xsl:namespace-alias>`
    20. `<xsl:number>`
    21. `<xsl:otherwise>`
    22. `<xsl:output>`
    23. `<xsl:param>`
    24. `<xsl:preserve-space>`
    25. `<xsl:processing-instruction>`
    26. `<xsl:sort>`
    27. `<xsl:strip-space>`
    28. `<xsl:stylesheet>`
    29. `<xsl:template>`
    30. `<xsl:text>`
    31. `<xsl:transform>`
    32. `<xsl:value-of>`
    33. `<xsl:variable>`
    34. `<xsl:when>`
    35. `<xsl:with-param>`

**Extensible Stylesheet Language Transformations (XSLT)** は XML ベースの言語で、XML 文書の変換をするために特別な処理ソフトウェア (プロセッサー) とともに利用されます。

この処理は「変換」と呼ばていれますが、元の文書は変更されません。この「変換」ではまず、新しい XML 文書が元の文書の内容をもとに作成され、プロセッサーによってそのまま、もしくは標準 XML や HTML やテキストなどの形式でシリアライズ (出力) されます。

XSLT は異なる XML スキーマ間でのデータの変換や、XML データからウェブページや PDF 文書への変換に最も使われています。

ドキュメント
------

XSLT 要素リファレンス

リファレンスです。

XSLT を使った XML 変換

XSLT を使うと、スタイルシートの制作者は、元の XML 文書を二つの重要な手法で変換できます。すなわち、コンテンツの操作・選別（もしお望みならば大規模な並べ替えも含まれます）および、異なる形式への変換です。

Mozilla JavaScript インターフェイスから XSLT を使う

Mozilla 1.2 以降の JavaScript から XSLT 処理エンジンへのインターフェイスを説明します。

処理命令を使った引数の指定

Firefox では `<?xml-stylesheet?>` 処理指令を使ってスタイルシートの引数を指定することができます。各引数は `<?xslt-param?>` 処理指令によって指定でき、この文書ではこれらを説明しています。

XSLT チュートリアル

この W3Schools のチュートリアルでは、XML 文書を他の XHTML のような形態に変換するために、どのように XSLT を用いればいいのかを示します。

XSLT とは?

この XSLT と XPath についての強力な導入では、技術についての予備知識が無い読者を想定して、背景、前後関係、構造、コンセプト、用語紹介を含めたガイドを提供します。

一般的な XSLT エラー

この記事は Firefox で XSLT を使う際の問題点を列挙しています。

関連トピック
------

* XML, XPath


テキストフラグメント

テキストフラグメント
==========

**テキストフラグメント**は、URL フラグメントの特定の構文を使用することにより、作成者が ID で注釈を付けなくても、ウェブ文書内のテキストの特定の部分に直接リンクできるようにするものです。対応しているブラウザーは、リンクされたテキストに注意を引く方法を自由に選べます。例えば、色の強調表示やページ上のコンテンツへのスクロールなどです。これは、ウェブコンテンツの作成者が、使用可能な ID が存在しなくても、制御下にない他のコンテンツに深くリンクすることができるため有益なものです。さらに、ユーザーが互いに交換するための、より効果的なコンテンツ共有リンクを生成するために使用することもできます。

概念と使用方法
-------

従来、ウェブの重要な機能の 1 つが、常に異なる文書の間にリンクを張る能力でした。

* 次のように、文書の URL にリンクすることで、その文書の先頭にリンクすることができます。
    + https://developer.mozilla.org/ja/docs/Web/HTML/Element/a
* 次のように、文書の URL にその節の *文書フラグメント* (ID) を加えたものにリンクすることで、文書の特定の節にリンクすることができます。
    + https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#ブラウザーの互換性

特定の文書フラグメントにリンクする場合の課題は、リンク先のページの作者が *実際に* リンクするためのアンカーを配置する必要があることです。上の 2 つ目の例は、h2 要素の ID が `ブラウザーの互換性` であるものにリンクしています。

```html
<h2 id="ブラウザーの互換性">
  <a href="#ブラウザーの互換性">ブラウザーの互換性</a>
</h2>
```

ID が変更または削除された場合、文書フラグメントは無視され、リンクはページの先頭にリンクされるだけです。これはグレイスフルデグラデーションの観点からは合理的ですが、リンクの作者がページの作者に頼る必要なく、リンク先を完全に制御することができれば、間違いなく良いことでしょう。

**テキストフラグメント**はこれを実現します。これにより、作者はリンク先のテキストコンテンツを、文書フラグメントではなく、柔軟な様式でリンクすることができます。

構文
--

テキストフラグメントは文書フラグメントと似た様式であり、URL の後にハッシュ記号 (`#`) を付けます。しかし、構文は多少異なります。
```

https://example.com#:~:text=[prefix-,]textStart[,textEnd][,-suffix]
```

理解が必要な主な部分は次の通りです。

`:~:`

この一連の文字は「フラグメントディレクティブ」とも呼ばれ、次に来るのが 1 つ以上のユーザーエージェント命令であることをブラウザーに指示します。これは、読み込む際に URL から取り除かれ、作成者のスクリプトが直接操作することはできません。ユーザーエージェント命令はディレクティブとも呼ばれます。

`text=`

テキストディレクティブです。これはブラウザーにテキストフラグメントを渡し、リンク先文書内のどのテキストにリンクされるかを定義します。

`textStart`

リンク先テキストの始まりを指定する文字列です。

`textEnd` 省略可

リンク先テキストの終わりを指定する文字列です。

`prefix-` 省略可

後にハイフンが付く文字列で、リンク先テキストの前に来るべきテキストを指定します。これは、複数の一致するテキストがある場合に、ブラウザーが正しいリンク先テキストを選択するために利用されます。

`-suffix` 省略可

前にハイフンが付く文字列で、リンク先テキストに続くテキストを指定します。これは、複数の一致するテキストがある場合に、ブラウザーが正しいリンク先テキストを選択するために利用されます。

対応しているブラウザーは、リンク先の文書内で指定したディレクティブと一致する最初のテキストフラグメントまでスクロールし、ハイライト表示します。なお、アンパサンド (`&`) 文字で区切ることで、同じ URL でハイライトする複数のテキストフラグメントを指定することが可能です。

### 使用上の注意

* `textStart`、`textEnd`、`prefix-`、`-suffix` の値はパーセントエンコードする必要があります。
* 照合時は、大文字小文字を区別しません。
* 個々の `textStart`、`textEnd`、`prefix-`、`-suffix` の文字列は、完全に同じブロックレベル要素内に存在する必要がありますが、照合処理全体では複数の要素境界をまたぐことができます。
* セキュリティ上の理由から、この機能ではリンクを noopener コンテキストで開く必要があります。この機能を使用する場合、`rel="noopener"` を `<a>` 要素に追加する必要があり、`window.open()` 呼び出し時には `noopener` を追加する必要があります。
* テキストフラグメントは、完全な（同じページでない）、ユーザー主導のナビゲーションの場合にのみ呼び出されます。
* テキストフラグメントはメインフレームにのみ適用されます。`<iframe>` の内部ではテキストは検索されませんし、`iframe` ナビゲーションではテキストフラグメントは呼び出されません。
* オプトアウトを希望するサイトのために、Chromium ベースのブラウザーは、ユーザーエージェントがテキストフラグメントを処理しないように送信できる文書ポリシーヘッダーの値に対応しています。

```http
Document-Policy: force-load-at-top
```

**メモ:** 指定されたテキストフラグメントがリンク先の文書内のどのテキストとも一致しない場合、またはブラウザーがテキストフラグメントに対応していない場合、テキストフラグメント全体が無視され、文書の先頭にリンクされます。

例
-

### textStart による単純なテキストフラグメント

* https://example.com#:~:text=for は、文書中の `for` という最初のテキストにスクロールし強調表示します。
* https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#:~:text=自然 は、文書中の `自然` という最初のテキストにスクロールし強調表示します。
* https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#:~:text=リンクされた%20URL は、文書中の `リンクされた URL` という最初のテキストにスクロールし強調表示します。
### textStart と textEnd

* https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#:~:text=自然言語,ヒント は、文書中の `自然言語` で始まり `ヒント` で終わる最初のテキストにスクロールし強調表示します。
* https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#:~:text=リンクされた%20URL,値を定義 は、文書中の `リンクされた URL` で始まり `値を定義` で終わる最初のテキストにスクロールし強調表示します。なお、この例ではテキストの強調表示が複数のブロックレベル要素をまたがって行われます。
### prefix- や -suffix の例

* https://example.com#:~:text=asking-,for は、文書中の `for` というテキストのうち 2 番目に出現するテキストにスクロールし強調表示します。
* https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#:~:text=送信される-,リファラー は、`送信される` というテキストが直前にある `リファラー` というテキストのうち最初のものにスクロールし強調表示します。これは文書中ので 2 番目の `リファラー` という文字列です。接頭辞がない場合は、最初のものが強調表示されます。
* https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#:~:text=リンク先の%20URL,-を表示 は、`リンク先の URL` というテキストの直後に `を表示` というテキストがある最初のものにスクロールし強調表示します。これは文書中ので 4 番目の `リンク先の URL` という文字列です。接尾辞がない場合は、最初のものが強調表示されます。
* https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#:~:text=downgrade:-,referer,ヘッダー,-は は、`Referrer ヘッダー` というテキストのうち、直前に `downgrade:` というテキストがあり、直後に `は` というテキストがあるものにスクロールし強調表示します。この例は、接頭辞/接尾辞を使用して、リンクしたい具体的なテキストインスタンスを絞り込む、より複雑な例を示しています。例えば接頭辞を削除して、何が一致するか試してみてください。
### 複数のテキストフラグメントが付いた URL

アンパサンド(`&`)文字で区切ることで、同じ URL で強調表示する複数のテキストフラグメントを指定することができます。

* https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#:~:text=リンクされた&text=扱う は、テキスト文字列 `Causes` および `linked` のうち最初に出現するものにスクロールし強調表示します。
* https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#:~:text=リンク先%20URL,-の&text=非推奨の-,属性,属性 は、2 つのテキストにスクロールし強調表示します。
    + `リンク先 URL` という文字列の直後に `の` がある最初のもの。
    + `属性` で始まり `属性` で終わるテキスト文字列で、その直前に `非推奨の` があるもの。

構文を正しく指定したはずなのに、複数のテキストフラグメントがハイライトされない場合、想定していたものとは異なる部分がハイライトされているだけかもしれません。ハイライトされていても、画面の外側に表示されている場合もあります。

### 一致するテキストフラグメントのスタイル付け

ブラウザーは、既定の方法でハイライトされたテキストを、自由にスタイル設定することができます。CSS 擬似要素モジュールレベル 4 では、`::target-text` 擬似要素を定義し、独自のスタイル付けができるようにしています。

例えば、scroll-to-text デモでは、次の CSS を使用しています。

```css
::target-text {
  background-color: rebeccapurple;
  color: white;
}
```

上記のリンクを対応するブラウザーで開くこと、その効果を確認することができます。

### テキストフラグメントへのプログラムからのアクセス

対応しているブラウザーでは、現在の文書で一致するテキストフラグメントの情報は `FragmentDirective` オブジェクトで得られ、 `Document.fragmentDirective` プロパティでアクセスすることができます。

対応するブラウザーの開発ツールで、1 つ以上の一致するテキストフラグメントがあるタブの中で、以下のものを実行してみてください。

```js
document.fragmentDirective;
```

以下のような構造を持つ `FragmentDirective` オブジェクトインスタンスが返されるはずです。

```js
items: [
  {
    prefix: "",
    textStart: "Module Workers",
    textEnd: "",
    suffix: "support",
    type: "text",
  },
  {
    prefix: "feedback on",
    textStart: "usability",
    textEnd: "",
    suffix: "",
    type: "text",
  },
];
```

この機能は、現在は主に機能検出を目的としていますが、将来的には、翻訳ヒントなど他の情報を記載するために展開することができます。

リファレンス
------

### API

`FragmentDirective`

現在の文書内の強調表示されたテキストフラグメントを表すオブジェクト。

`Document.fragmentDirective`

現在の文書の `FragmentDirective` を返す。

### CSS

`::target-text`

現在の文書内の強調表示されたテキストフラグメントを表します。作成者がテキストフラグメントのスタイル設定をカスタマイズすることができます。

仕様書
---

| Specification |
| --- |
| URL Fragment Text Directives # fragmentdirective |
| CSS Pseudo-Elements Module Level 4 # selectordef-target-text |

ブラウザーの互換性
---------

### html.elements.a.text\_fragments

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### api.FragmentDirective

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### css.selectors.target-text

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* Boldly link where no one has linked before: Text Fragments


CSS: カスケーディングスタイルシート

CSS: カスケーディングスタイルシート
====================

**カスケーディングスタイルシート** (Cascading Style Sheets、**CSS**) はスタイルシート言語であり、HTML や XML (方言である SVG、MathML、XHTML などを含む) で記述された文書の体裁や見栄えを表現するために用いられます。 CSS は、要素が画面上で (あるいは紙や音声といった別のメディア上で) どのように表現されるのかを定義します。

CSS は**オープンウェブ**の核となる言語に含まれており、W3C 標準仕様によってウェブブラウザー間で標準化されています。以前は CSS 仕様書の様々な部分が同時に開発されており、最新勧告の版数付けができていました。皆さんも CSS1、CSS2.1、また CSS3 についても聞いたことがあるでしょう。CSS3 や CSS4 にはなりません。すべてバージョン番号のない CSS になりました。

CSS 2.1 以降、仕様の範囲が大幅に拡大し、CSS モジュールごとに進捗状況が大きく異なるようになったため、モジュールごとに勧告を開発して公開することがより効果的になりました。W3C では、CSS 仕様のバージョン管理の代わりに、最新の CSS 仕様の安定した状態のスナップショットと独立したモジュールの進捗を定期的に取得するようになりました。CSS のモジュールは、CSS Color Module Level 5 のように、バージョン番号またはレベルを持つようになりました。

主なリソース
------

CSS 入門

ウェブ開発が初めての人は、CSS の基本の記事を読んで、CSS とは何か、どのように使用するかを学習しましょう。

CSS チュートリアル

CSS 学習領域は、初心者から中級者になるための、すべての基本事項を網羅した豊富なコンテンツがあります。

CSS リファレンス

CSS のすべてのプロパティや概念について記述された、熟練のウェブ開発者向けの包括的な CSS リファレンスです。

#### フロントエンドのウェブ開発者を目指している方へ

ゴールに向かって頑張るために必要な情報をまとめたコースをご用意しました。

**始めましょう**

チュートリアル
-------

CSS 学習領域 は基礎から CSS を教える複数のモジュールにスポットを当てています — 事前の知識は必要ありません。

CSS の第一歩

CSS (Cascading Style Sheets) はウェブページをスタイル付けしたりレイアウトしたりするのに使われます。例えば、文字、色、大きさを変えたり、コンテンツに余白を設けたり、複数列に分けたり、あるいはアニメーションを加えたりなど様々な装飾機能があります。このモジュールでは CSS を習得するために、どう働くかの基本とともに、構文のありかたと HTML にスタイル付けを加えることを簡単な始め方を提供します。

CSS の構成要素

このモジュールは CSS の第一歩が終わったところを引き継いでいます。言語とその構文に慣れてきて、基本的な使用経験を積んだところで、もう少し深く掘り下げてみましょう。このモジュールでは、カスケードと継承、利用可能なすべてのセレクターのタイプ、単位、寸法の調整、背景や境界のスタイル付け、デバッグなど多くのことを見ていきます。

ここでの目的は、テキストの装飾やCSS レイアウトなどのより具体的な分野に進む前に、適切な CSS を書くための手法を知り、すべての重要な理論を理解できるようになることです。

CSS テキスト装飾

CSS 言語の基本を習得したら、次に取り組むべき CSS のトピックはテキストの装飾です — これは、CSS で行う最も一般的なことの一つです。ここでは、フォント、太字、イタリック体、ラインと文字の間隔、ドロップシャドウやその他のテキスト機能の設定を含む、テキストの装飾の基本を見ていきます。あなたのページにカスタムフォントを適用し、リストとリンクを装飾するところを見ることによって、このモジュールを締めくくります。

CSS レイアウト

現段階で、すでに CSS の基本、テキストの装飾方法、コンテンツを格納するボックスの装飾方法と操作方法を見てきました。今度は、ビューポートからの相対でボックスを適切な場所に配置する方法、および互いの配置方法を検討します。必要な前提知識をカバーしているので、さまざまな表示の設定、フレックスボックス・CSS グリッド・位置指定などの最新のレイアウトツール、そしてまだ知っておきたいと思うかもしれない過去のテクニックのいくつかを見ながら、CSS レイアウトについて深く掘り下げることができます。

CSS を使ってよくある問題を解決する

このモジュールは、ウェブページを作成する際の一般的な問題を解決するための CSS の使用方法を説明するコンテンツの節へのリンクを提供しています。

リファレンス
------

* CSS リファレンス: CSS のすべてのプロパティや概念について記述された、熟練のウェブ開発者向けの CSS リファレンスです。
* CSS の主要な概念:
    + 言語の構文と書式
    + 詳細度と継承とカスケード
    + CSS 単位と値および関数記法
    + ボックスモデルとマージンの相殺
    + 包含ブロック
    + 重ね合わせとブロック整形コンテキスト
    + 初期値、計算値、使用値、実効値
    + CSS 一括指定プロパティ
    + CSS フレックスボックスレイアウト
    + CSS グリッドレイアウト
    + CSS セレクター
    + メディアクエリー
    + アニメーション
料理帳
---

CSS レイアウト料理帳は、よくあるレイアウトパターンや、サイトに実装する必要がある可能性がある事柄のレシピを共有するためのものです。プロジェクトの出発点として使うことができるコードを提供することに加えて、これらのレシピは様々な方法のレイアウト仕様書を使用することができることに光を当て、開発者として選択ができるようにします。

CSS 開発のためのツール
-------------

* W3C CSS Validation Service は CSS が正しく書かれているかを判定するために利用できます。デバッグのために重宝するツールです。
* Firefox Developer Tools はインスペクターとスタイルエディターツールを通じて、ページの CSS をライブでの閲覧や編集を可能にします。
* Firefox のウェブ開発者拡張機能では、表示しているサイトをその場で追跡したり編集したりすることができます。
メタバグ
----

* Firefox: Firefox バグ 1323667
関連情報
----

* CSS のデモ: 最新の CSS テクノロジーの例を探索して想像力をかきたてましょう。
* CSS がよく適用されるウェブ言語。HTML、SVG、MathML、XHTML、XML
* CSS に関する Stack Overflow の質問


MathML

MathML
======

**Mathematical Markup Language (MathML)** は、数学的表記を記述し、その構造と内容を表現するための XML マークアップ言語です。

このページには、MathML のパワフルな技術を用いた仕事を助けるための文書、サンプル、ツールへのリンクがあります。簡単な概要は、Mozilla Summit 2013 で行われた innovation fair 向けのスライド をご覧ください。

MathML リファレンス
-------------

MathML 要素リファレンス

各 MathML 要素の詳細とデスクトップおよびモバイルのブラウザの互換性情報。

MathML 属性リファレンス

MathML 要素の見た目や振る舞いを変更する MathML 属性についての情報。

MathML の例

MathML の動作についての理解を深めるためのサンプルと例。

MathML の書き方

MathML を書くための提案とヒント、おすすめの MathML エディター、その出力をウェブコンテンツへ統合する方法。

コミュニティから助けを得る
-------------

* mozilla.dev.tech.mathml Google Group
* Mozilla 貢献者の使う Wiki
* W3C Math Home
* www-math w3.org メールアーカイブ
ツール
---

* W3C Validator
* Mathzilla Firefox アドオンコレクション
* TeXZilla — Javascript で書かれた LaTeX から MathML へのコンバーター (ライブデモ、Firefox アドオン、ウェブページや JS プログラム内での使用)
* LaTeXML - LaTeX ドキュメントを HTML+MathML ウェブページへ変換
* MathJax - 数式のためのクロスブラウザー JavaScript 表示エンジン。MathJax をネイティブ MathML で使用するには、Mozilla アドオン、Safari 拡張、GreaseMonkey スクリプト を試してください。
関連トピック
------

* CSS
* HTML
* SVG
ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


プライバシー、権限、情報セキュリティについて

プライバシー、権限、情報セキュリティについて
======================

ユーザーが日常的にウェブを使用するようになると、プライベートな情報や個人を特定する情報を共有することが多くなりますが、できれば信頼できるサイトとだけ共有したいものです。そのため、コンテンツ、ウェブブラウザー、ウェブサーバーが連携して、プライバシーや情報セキュリティの確保に努めることが必要です。この記事では、ユーザーの個人情報や画像が第三者に意図せず取得されるリスクを最小化するウェブコンテンツを作成する方法について検討します。

セキュリティとプライバシーの定義
----------------

ウェブ上でユーザーが利用できるさまざまなセキュリティやプライバシー機能について詳しく説明する前に、いくつかの重要な用語を定義しておきましょう。

個人を特定できる情報

個人を特定できる情報 (Personally identifiable information, PII) とは、その全部または一部を使用して、特定の個人を追跡したり、特定したりすることができる情報のことです。そのため、PII はウェブにとどまらず、生活のすべての場面に及んでいます。例えば、あるサイトがユーザーの名前と郵便番号のリストをオンライン上に流出させた場合、悪い業者は、対応する電話帳を使用することで、そのユーザーの少なくとも何割かを特定できることはほぼ間違いありません。

個人を特定する情報には、ユーザー名、本名、パスワード、電話番号や住所（あるいはその一部）、病歴に関する情報、社会保障番号、運転免許証、あるいはその他IDやID番号の形成する形式、クレジットカード情報などを含めることができます。とても広い範囲の情報です。データを作業するときは、常に立ち止まって考えてください。多くの手順を経て、ある人物を特定するために使用できる方法はないでしょうか？

プライバシー

プライバシーの概念を定義するのは、やや困難です。何かを秘密にすることの意味については、誰もが何らかの考えを持っていますが、データのプライバシーについて話すときは、それが不明瞭になります。基本的に、インターネット上のデータのプライバシーとは、個人的な意味を持つ情報を、その入手方法にかかわらず、権限のない人や組織の手に渡らないようにすることを意味します。

プライバシーの例外は、特定のサイトやアプリケーションに対して認められることもありますが、一部の人だけにアクセスを許可したり、限られた時間だけ情報へのアクセスや使用を許可したりするなど、条件付きで認められることもあります。

セキュリティ

セキュリティとは、データやシステムを、その権限を持たない人や組織によってアクセスされたり、ダウンロードされたり、運営されたりしないように、積極的に保護することをいいます。優れたセキュリティ対策は、対象とするものが何であれ、システムやデータへの不正なアクセスを防止することを目的としています。

個人・プライベート情報
-----------

プライバシーリスク
---------

### フィンガープリント

**フィンガープリント**は、ユーザーのブラウザーによって利用できるさまざまな情報を収集し、そのユーザーのブラウザーを一意に識別できるようになるまで照合するために使用される技術です。一見無害な情報でも、原理的にはフィンガープリント作業に使用することができますが、特定の機器に固有の情報であればあるほど、より効果的です。

現代のブラウザーは、情報へのアクセスを許可しないか、情報を利用できるようにする必要がある場合は、識別のために使用することを防ぐ様々な方法を導入することによって、フィンガープリントに基づく攻撃を防ぐのに役立つ措置を講じています。

例えば、ウェブサイトがユーザーのブラウザーに経過時間を問い合わせた場合、その時刻とサーバーが報告した時刻を比較することで、フィンガープリントの要因として有益なものとなる可能性があります。このため、ブラウザーは通常、タイマーをユーザーシステムの識別に使用されにくくするために、タイマーに少量の変動を導入しています。

新しいプライバシー技術
-----------

ウェブブラウザーは、プライバシー空間を改善する新しい機能に積極的に取り組んでいます。

プライバシーとセキュリティの制御
----------------

セキュリティやプライバシーの侵害からユーザーを守るための支援として、複数の制御レイヤーがあります。これらは、ネットワーク上で使用される通信層を含むウェブサーバーから始まり、ウェブブラウザーのセキュリティ機能を経て、ウェブアプリケーションのコードに到達し、それ自身とユーザーが託したデータを保護するために取る努力に至ります。

プライバシーとセキュリティを管理するために、いくつかのウェブ技術や機能があります。以下のリストは、これらの機能の多くが両方に使用されるため、両方に影響を与える機能を記載しています。

セキュリティとプライバシーを強化するために使用されるウェブ技術と機能| 技術または機能 | 説明 |
| --- | --- |
| 資格情報の透明性 | 証明書を監視・監査するためのオープンスタンダードで、不正な証明書や悪意のある証明書の特定に支援するために使用できる公開ログのデータベースを作成します。 |
| コンテンツセキュリティポリシー | 文書内のコンテンツがウェブ上で他の機器からアクセスできる範囲を定義する機能を提供した。特にサーバーへの攻撃を防止または軽減するために使用できる。 |
| HTTP Strict Transport Security (HSTS) | HSTS は、サイトがクライアントに対してサーバーとの通信に HTTPS のみを使用することを指示することによって、プロトコルのダウングレードやクッキーハイジャック攻撃から自身を保護するためにサーバーから使用されます。 |
| HTTP/2 | HTTP/2 は技術的には暗号化を使用する必要はありませんが、ほとんどのブラウザー開発者は HTTPS と併用する場合のみ対応しているので、その点でセキュリティに関連していると考えることもできます。 |
| 権限 API | 現在のブラウザーコンテキストに対する権限の状態を判断する方法を提供します。 |
| 権限ポリシー |
 ウェブサーバーが `<iframe>` で読み込んだ文書とサブ文書の両方で、`Permissions-Policy` を介して機能や API を選択的に有効または無効にできるようにします。
 `allow` 属性は、個々の `<iframe>` に権限ポリシーを設定するために使用できます。
  |
| Transport Layer Security
 (TLS)、以前は Secure Sockets Layer (SSL) と呼ばれていました
  | TLS は、ネットワーク上での転送中にデータを暗号化することで、セキュリティとプライバシーを提供します。これは、HTTPS (HyperText Transport Protocol Secured) プロトコルを支える技術です。 |

個人情報の安全管理
---------

サイトの権限の管理
---------

すべての統合
------

### <iframe> 要素内の権限リクエスト

ウェブアプリケーションが `<iframe>` 要素を使用して他のサイトのコンテンツを自分のサイト内に埋め込む場合、特にフレームに読み込む文書にその権限を考える必要がある場合は、厄介なことになることがあります。

これらの技術の仕様は、このような状況を処理するための戦術を表明または推奨していますが、ブラウザーは、セキュリティをさらに向上させたり、新しい機能を試したり、ユーザーにとっての複雑さを軽減したりするために、異なる解決策を提供する可能性があり、他にもさまざまな理由が考えられます。

リソースへのアクセスを許可して読み込んだ文書が、`<iframe>` の中に `allow` 属性を含んでいて、その許可をフレームのコンテンツに委任している場合、使い勝手の問題が生じることがあります。この場合、ユーザーは同じリソースを繰り返しリクエストされることになり、最初はメインページ、次にフレーム内の文書でリクエストされる可能性があります。

ブラウザーは、これを回避する方法を提供することができます。例えば、Firefox 73 では、ユーザー権限リクエストが修正され、`<iframe>` が `allow` キーワードを使用して埋め込み文書に権限を委譲する場合、ブラウザーは親文書にリソースを使用する権限を与えるようユーザーに要求し、その権限はリソースをリクエストした埋め込みコンテンツと共有され、始めに使用します。

関連情報
----

* ウェブセキュリティ
* 権限 API
* 権限ポリシー
* The Privacy Sandbox


チュートリアル

チュートリアル
=======

このページには、さまざまなチュートリアルとトレーニング用教材へのリンクがあります。これからウェブ開発を始めようとしている方、基礎を学ぼうとしている方、ウェブ開発に慣れている方など、ベストプラクティスを学習するのに役立つ教材をここで見つけることができます。

これらの教材は、先見の明のある企業やウェブ開発者が、オープン標準やウェブ開発のベストプラクティスを支持して、クリエティブ・コモンズなどのオープンコンテンツライセンスに準じて提供や翻訳を許可しています。

ウェブについて全くの初心者の人たちへ
------------------

ウェブ入門

*ウェブ入門*は、実用的なウェブ開発の入門シリーズです。まずはじめに、簡単なウェブページを作るのに必要なツールを準備します。そして、簡単なコードを書いたら、それを実際にウェブに公開します。

HTML チュートリアル
------------

### 入門レベル

HTML 入門

HTML とは何か、HTML がどのように動くか、HTML の簡単な歴史について、HTML 文書の構造がどのようなものかを解説します。次に、HTML の構成部分をそれぞれ詳細に見ていきます。

MDN HTML 要素リファレンス

HTML 要素の包括的なリファレンスです。ブラウザーごとの対応状況も分かります。

Creating a Simple Web Page with HTML（英語）

この HTML ガイドは、初心者向けに HTML タグを含めた、よくあるタグを紹介しています。また、段階ごとに基本的なウェブページを作成するためのコード例を載せています。

HTML Challenges（英語）

問題に挑戦し HTML のスキルを磨きましょう。マークアップが意味のあるものになっているか (例: <h2> か <strong> のどちらをを使うべきか) がポイントです。

### 中級レベル

マルチメディアと埋め込み

このモジュールでは、ウェブページに、HTML をどのようにして用いればマルチメディアを含むことができるかについて学びます。また、画像を挿入するためのさまざまな方法や、どのようにして動画・音声、そして他のウェブページ全体を挿入するのかについても触れています。

HTML 表

ウェブページにおいて、表の形のデータを理解可能な形、そしてアクセシビリティに配慮した形で表現することは少し難しいでしょう。このモジュールは、基本的な表のマークアップ、そしてさらに注や要約を付加など、もっと複雑な機能を扱います。

### 上級レベル

HTML フォーム

HTML フォームは、ウェブの重要な部品です。フォームは多くの機能を提供し、ユーザーがウェブサイトとやり取りする際に必要なものとなっています。例えば登録、ログイン、フィードバックの送信、商品の購入、などなど。このモジュールではフォームのクライアント側の部分を作成するところから始めます。

読み込みが速い HTML ページを作成するヒント

ウェブページを最適化することでサイト表示の待ち時間を短くし、サーバーとインターネット接続経路の負荷を軽減する方法を学ぶことができます。

CSS チュートリアル
-----------

### 入門レベル

CSS の基本

CSS (Cascading Style Sheets) は、ウェブページのスタイルを設定するコードです。CSS の基本ではあなたが始めるのに必要なものを紹介します。私たちは次のような質問に答えます：テキストを黒または赤にするにはどうすればいいですか？ そのような場所でコンテンツを画面に表示させるにはどうすればよいですか？ 背景画像と色を使ってウェブページをどのように飾るのですか？

CSS 入門

CSS (Cascading Style Sheets) は、ウェブページのスタイルづけやレイアウトに使用されます。例えば、コンテンツのフォント、色、サイズ、間隔を変更したり、複数の段に分割したり、アニメーションやその他の装飾機能を追加したりすることができます。このモジュールでは、 CSS がどのように機能するか、どのような構文になっているか、そして HTML にスタイルを追加するためにどのように使い始めるか、といった基本的な内容で、 CSS マスターへの道を順番に始めます。

CSS の構成要素

このモジュールは CSS 入門の続きです。言語とその構文に慣れ、基本的な使用方法を身につけたところで、もう少し深く掘り下げてみましょう。このモジュールでは、カスケードと継承、利用可能なすべてのセレクターの種類、単位、サイズ調整、背景や境界線のスタイル、デバッグなどについて学びます。

このモジュールの目的は、有能な CSS を書くためのツールキットを提供し、テキストのスタイル付けや CSS レイアウトなどのより具体的な分野に進む前に、すべての基本的な理論を理解してもらうことです。

セレクター

HTML 要素を、要素の状態に基づくなどして、CSS で対象とします。

詳細度

ある要素に競合する宣言がある場合、どの CSS 宣言が適用されるかを決定するためのブラウザーアルゴリズムを、詳細度クイズ（英語）を使って理解します。

カスケードと継承

カスケード、詳細度、継承は、CSS がどのように HTML に適用され、スタイル宣言間の競合がどのように解決されるかを制御します。

テキストのスタイル付け

ここでは、フォント、太字、イタリック体、線、文字間隔、影、その他のテキストの機能の設定を含むテキストのスタイル付けの基礎を確認します。ページにカスタムフォントを適用し、リストとリンクにスタイルを適用することでこのモジュールを締めくくります。

CSS に関するよくある質問

初心者から寄せられるよくある質問とその回答です。

### 中級レベル

CSS レイアウト

この時点で、 CSS の基本、テキストスタイルの設定方法、コンテンツが内部にあるボックスのスタイルと操作方法については説明を終えています。今度は、ボックスを表示領域に関連して適切な場所に配置する方法を見てみましょう。必要な堰堤条件についてはすでに終えているので、 CSS のレイアウト、様々な display の設定、浮動 (float) と位置指定 (positioning) を含む従来のレイアウト方法、フレックスボックスのような新しいレイアウトツールなどについて詳しく調べることができます。

CSS リファレンス

CSS の完全なリファレンスです。Firefox やその他のブラウザーの対応の詳細もあります。

Fluid Grids（英語）

前からある植字用のグリッドを使いながら、ブラウザーのウィンドウに合わせて可変的にリサイズするレイアウトを設計することができます。

CSS Challenges（英語）

CSS スキルを確認し、何を勉強すべきかを知ることができます。

### 上級レベル

CSS 座標変換の使用

CSS を使って、回転、傾き、拡大、縮小、移動を行います。

CSS トランジション

CSS トランジションでは、CSS プロパティの変化を即時に行うのではなく、アニメーションで行う方法を提供します。

Canvas チュートリアル

canvas 要素を使用するスクリプトを書いてグラフィックを描く方法を学ぶことができます。

JavaScript チュートリアル
------------------

### 入門レベル

JavaScript の第一歩

最初の JavaScript のモジュールでは、初めて JavaScript を書く実践的な体験をしていただく前に「JavaScript とは何？」や「どのように見える？」や「何ができる？」といったような基本的な質問に答えます。その後 JavaScript を理解する重要な特徴、たとえば変数や文字列、数値、配列などについてお話します。

JavaScript の構成要素

このモジュールでは、条件付きステートメント、ループ、関数、イベントなど一般的に発生するコードブロックの種類に注目し、JavaScript の重要な基本機能をすべてカバーしていきます。これまでの勉強で詰め込み、とおりすぎてしまっているかもしれませんが、ここではすべて明示的に説明を行います。

JavaScript を始める

JavaScript とは何か? 何の役に立つのかを学べます。

Codecademy（英語）

Codecademy では簡単に JavaScript コーディングの方法を学べます。対話形式で学習でき、友人と一緒に進めることができます。

freeCodeCamp（英語）

では、ウェブ開発のための様々な言語やフレームワークを教えています。フォーラム、インターネットラジオ局、ブログもあります。

### 中級レベル

JavaScript オブジェクトの紹介

JavaScript では、文字列や配列などの JavaScript のコア機能から、JavaScript の上に構築されたブラウザー API まで、ほとんどのものがオブジェクトです。関連する関数や変数を効率的なパッケージにカプセル化する独自のオブジェクトを作成することもできます。 JavaScript のオブジェクト指向の性質を理解することは、言語に関する知識をさらに深め、より効率的なコードを書く場合に重要です。したがって、このモジュールを用意しました。ここではオブジェクトの理論と構文を詳しく説明し、独自のオブジェクトを作成する方法を見て、JSON のデータとその使い方を説明します。

クライアント側ウェブ API

ウェブサイトやアプリケーションのためにクライアント側 JavaScript を書くとき、API (様々なブラウザーやサイトを動かしている OS 、さらに他のウェブサイトやサービスのデータを操作するインターフェイス) の使用が不可欠です。このモジュールでは、API とはどういったものかや開発の多くで使われる最もよくある API の使い方を調べられます。

Eloquent JavaScript（英語）

JavaScript の中級・上級の方法論への包括的ガイドです。

Speaking JavaScript（英語）

JavaScript の学習をすばやく正確に学びたいプログラマーや特定のトピックスを探したり、スキルを上げたいプログラマーのためのサイトです。

Essential JavaScript Design Patterns（英語）

基本的な JavaScript デザインパターンの紹介です。

JavaScript.info - The Modern JavaScript Tutorial（英語）

第 1 部: 言語。第 2 部: ブラウザーでの作業。

### 上級レベル

JavaScript ガイド

初心者から上級者まですべてのレベル向けの分かりやすい JavaScript ガイドです。定期的に更新されています。

You Don't Know JS（英語）

このシリーズは、JavaScript のコアなメカニズムを深める本です。

JavaScript Garden（英語）

JavaScript で最もはまりやすい部分をドキュメント化したものです。

Exploring ES6（英語）

ECMAScript 2015 の信頼できる詳しい情報元です。

JavaScript Patterns（英語）

Javascript のパターンと不適切な例であるアンチパターンを集めたものです。関数パターン、jQuery パターン、jQuery プラグイン パターン、デザイン パターン、よくあるパターン、リテラルおよびコンストラクター パターン、オブジェクト生成パターン、コード再利用パターン、DOM をカバーしています。

How browsers work（英語）

モダンブラウザーのエンジンやページレンダリングなどの違いが詳しく研究され、説明された論文です。

JavaScript Videos (GitHub)

見ておきたい JavaScript についての映像を集めたものです。

### 拡張機能の開発

WebExtensions

WebExtensions は、ブラウザーのアドオンを開発するための、ブラウザー間互換システムです。多くの部分において、このシステムは Google Chrome や Opera が対応している拡張機能 API と大体において互換性があります。これらのブラウザー用に書かれたアドオンは大抵の場合、 Firefox や Microsoft Edge でも ほんの少し変更を加えるだけで、動かすことができます。この API はマルチプロセス Firefox とも完全な互換性があります。


ウェブアプリマニフェスト

ウェブアプリマニフェスト
============

**ウェブアプリマニフェスト**は、プログレッシブウェブアプリ (PWA) と呼ばれる一連のウェブ技術の一部であり、アプリストアを通さずに端末のホーム画面にインストールすることができるものです。単純なホーム画面リンクやブックマークを持つ通常のウェブアプリとは異なり、 PWA は事前にダウンロードしてオフラインでも動作するだけでなく、通常の Web API を使用することもできます。

ウェブアプリマニフェストは、ウェブアプリケーションについて、ウェブアプリをダウンロードしたり、ユーザーにネイティブアプリと同じように見せる（例えば、端末のホーム画面にインストールされ、ユーザーに素早いアクセスと豊かな操作性を提供するなどの）ために必要な情報を JSON テキストファイルで提供します。 PWA のマニフェストには、その名前、作者、アイコン、バージョン、説明、および (他のものの中で特に) 必要なすべてのリソースのリストが含まれています。

メンバー
----

ウェブマニフェストには、以下のキーを設定することができます。それぞれのリンクをクリックすると詳細情報を見ることができます。

* background\_color
* categories
* description
* display
* display\_override
* icons
* id
* name
* orientation
* prefer\_related\_applications
* protocol\_handlers
* related\_applications
* scope
* screenshots
* share\_target
* short\_name
* shortcuts
* start\_url
* theme\_color
マニフェストの例
--------

```json
{
  "$schema": "https://json.schemastore.org/web-manifest-combined.json",
  "name": "HackerWeb",
  "short\_name": "HackerWeb",
  "start\_url": ".",
  "display": "standalone",
  "background\_color": "#fff",
  "description": "読みやすいハッカーニュースアプリです。",
  "icons": [
    {
      "src": "images/touch/homescreen48.png",
      "sizes": "48x48",
      "type": "image/png"
    },
    {
      "src": "images/touch/homescreen72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "images/touch/homescreen96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "images/touch/homescreen144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "images/touch/homescreen168.png",
      "sizes": "168x168",
      "type": "image/png"
    },
    {
      "src": "images/touch/homescreen192.png",
      "sizes": "192x192",
      "type": "image/png"
    }
  ],
  "related\_applications": [
    {
      "platform": "play",
      "url": "https://play.google.com/store/apps/details?id=cheeaun.hackerweb"
    }
  ]
}
```

マニフェストの展開
---------

ウェブアプリマニフェストは、文書の `<head>` 内の `<link>` 要素を使用して HTML ページから展開されます。

```html
<link rel="manifest" href="manifest.json" />
```

`.webmanifest` の拡張子が仕様書の Media type registration の節で指定されています（マニフェストファイルのレスポンスは `Content-Type: application/manifest+json` を返してください）。ブラウザーは一般に `.json` (`Content-Type: application/json`) のような他の適切な拡張子でもマニフェストに対応します。

マニフェストへのアクセスに資格情報が必要な場合は、マニフェストファイルが現在のページと同じオリジンにあったとしても、 `crossorigin` 属性を `use-credentials` に設定する必要があります。

```html
<link rel="manifest" href="/app.webmanifest" crossorigin="use-credentials" />
```

スプラッシュ画面
--------

一部のブラウザー（例えば Chrome 47 以降）では、ホーム画面からサイトが起動されるとスプラッシュ画面が表示されます。スプラッシュ画面はウェブアプリマニフェストのプロパティから、具体的には以下のように自動生成されます。

* `name`
* `background_color`
* `icons` の配列中のアイコンで、端末の 128dpi に最も近いもの。
仕様書
---

| 仕様書 |
| --- |
| Web App Manifest |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* プログレッシブウェブアプリ (PWA)


JavaScript

JavaScript
==========

**JavaScript** (**JS**) は軽量で、インタープリター型、あるいは実行時コンパイルされる、第一級関数を備えたプログラミング言語です。ウェブページでよく使用されるスクリプト言語として知られ、多くのブラウザー以外の環境、例えば Node.js や Apache CouchDB や Adobe Acrobat などでも使用されています。 JavaScript はプロトタイプベースで、マルチパラダイムで、シングルスレッドで、動的な言語であり、オブジェクト指向、命令型、宣言型（関数プログラミングなど）といったスタイルに対応しています。

JavaScript の動的な機能には、ランタイムオブジェクトの構築、可変引数リスト、関数変数、動的スクリプトの作成（`eval` で）、オブジェクトの内包（`for...in` と `Object` ユーティリティで）、ソースコードの復元（JavaScript 関数はそのソーステキストを格納し `toString()` で復元可能）が含まれます。

この章では JavaScript 言語自体について、すなわちウェブページや他のホスト環境に限定されないコアの部分に限定して解説しています。ウェブページ特有の API 群の情報を得たい場合は Web API と DOM を参照してください。

JavaScript の規格書は ECMAScript Language Specification および ECMAScript Internationalization API specification (ECMA-402) です。私たちは、あるブラウザーが機能を実装するとすぐに、それを文書化するように努めています。このことは、 ECMAScript の新しい機能に関するいくつかの提案がすでにブラウザーに実装されている場合、MDN の記事の文書や例ではそれらの新しい機能のいくつかを使用する可能性があることを示しています。ほとんどの場合、これはステージ 3 と 4 の間で起こることで、通常は仕様が正式に公開される前です。

JavaScript をプログラミング言語 Java と混同しないでください。 **JavaScript は「インタープリター版の Java」では *ありません***。 "Java" と "JavaScript" は両方ともアメリカやその他の国においてオラクルの商標または登録商標です。しかし、この 2 つのプログラミング言語は構文、セマンティック、利用形態が大きく異なります。

コア言語機能の JavaScript ドキュメントは（多くの部分は純粋な ECMAScript）、以下のものがあります。

* JavaScript ガイド
* JavaScript リファレンス

JavaScript 仕様と関連技術に関する詳細は、 JavaScript 技術概要を参照してください。

**フロントエンドのウェブ開発者を目指している方へ**

ゴールに向かって頑張るために必要な情報をまとめたコースをご用意しました。

**始めましょう**

チュートリアル
-------

ガイドやチュートリアルを使って JavaScript をプログラムする方法を学びましょう。

### 完全な初心者向け

JavaScript について学びたいと思っているが、JavaScript あるいはプログラミングについて過去に経験がないのであれば、 JavaScript 学習エリアのトピックに向かいましょう。以下のモジュールが利用可能です。

JavaScript の第一歩

変数、文字列、数値、配列のような JavaScript の基本機能の解説に加え、「JavaScript とは何か」「何に似ているか」「何ができるか」といった基本的な質問に答えます。

JavaScript の構成要素

引き続き JavaScript の基本機能について、条件分岐、ループ、関数、イベントなどのよく目にするタイプのコードブロックに注意を向けつつ説明します。

JavaScript のオブジェクトの紹介

言語に関する知識をさらに深め、より効率的なコードを書きたいのであれば、JavaScript のオブジェクト指向の性質を理解することは重要です。このため、私たちが提供するこのモジュールが役立つでしょう。

非同期 JavaScript

非同期 JavaScript について、なぜ重要なのか、どのように使用してサーバーからのリソースの読み取りなどのブロックが発生する可能性がある操作を効果的に扱うことができるのかを説明します。

クライアント側ウェブ API

API とは何か、開発作業でよく見かける、最も一般的な API の一部の使い方を説明します。

### JavaScript ガイド

JavaScript ガイド

JavaScript や他の言語でのプログラミング経験がある方を対象とした、より詳細な JavaScript 言語のガイドです。

### 中級者向け

クライアント側の JavaScript フレームワークの理解

JavaScript フレームワークは、最新のフロントエンドウェブ開発に欠かせないもので、拡張性のある双方向のウェブアプリケーションを構築するための、試行錯誤されたツールを開発者に提供します。幾つかの有名なツールについて取り扱うチュートリアルに移動する前に、クライアントサイドのフレームワークがどのように動作するのか、自分のツールセットにどのように適合させるか、についての基本的な背景知識を提供します。

JavaScript 言語概要

他のプログラミング言語から来た人がスピードアップするために、 JavaScript の基本的な構文と意味づけの概要を説明します。

JavaScript のデータ構造

JavaScript で利用可能なデータ構造の概要です。

等値比較と同一性

JavaScript には 3 つの異なる値の比較演算子があります。 `===` を用いる厳格な等値性比較、 `==` を用いる緩い等値性比較、そして `Object.is()` メソッドです。

プロパティの列挙と所有権

オブジェクトプロパティのグループを1つずつ訪問する様々なメソッドが、プロパティの列挙可能性と所有権をどのように処理するかです。

クロージャ

クロージャとは、関数とその関数が宣言された字句環境の組み合わせのことです。

### 上級者向け

継承とプロトタイプチェーン

よく誤解されたり過小評価されたりしているプロトタイプベースの継承に対する説明です。

メモリー管理

JavaScript におけるメモリーのライフサイクルとガベージコレクションです。

同時実行モデルとイベントループ

JavaScript は「イベントループ」に基づく同時実行モデルを持っています。

リファレンス
------

完全な JavaScript リファレンスドキュメントをご覧ください。

標準オブジェクト

標準組み込みオブジェクトである `Array`, `Boolean`, `Date`, `Error`, `Function`, `JSON`, `Math`, `Number`, `Object`, `RegExp`, `String`, `Map`, `Set`, `WeakMap`, `WeakSet` などについて理解しましょう。

式と演算子

JavaScript の演算子である `instanceof`, `typeof`, `new`, `this` などの挙動、そして演算子の優先順位などについて学びましょう。

文と宣言

`do-while`, `for-in`, `for-of`, `try-catch`, `let`, `var`, `const`, `if-else`, `switch` などの JavaScript の文やキーワードがどのように機能するか学びましょう。

関数

JavaScript の関数を使ってアプリケーションを開発する方法を学びましょう。

クラス

JavaScript のクラスはオブジェクト指向プログラミングを行う上で最適な方法です。


イベントの作成と起動 - イベントリファレンス

イベントの作成と起動
==========

この記事では、 DOM イベントを作成して処理する方法を説明します。このようなイベントは、一般に、ブラウザー自体によって起動されたイベントとは対照的に、**合成イベント**と呼ばれます。

カスタムイベントの作成
-----------

イベントは、次のように `Event` コンストラクターを使用して作成できます。

```js
const event = new Event("build");

// Listen for the event.
elem.addEventListener(
  "build",
  function (e) {
    /\* ... \*/
  },
  false,
);

// Dispatch the event.
elem.dispatchEvent(event);
```

上記のコード例は EventTarget.dispatchEvent() メソッドを使用します。

このコンストラクターは、ほとんどの最新のブラウザーでサポートされています (Internet Explorer は例外です)。もっと冗長的なアプローチ (Internet Explorer で動作するもの) は、下記の古い方法を参照して下さい。

### カスタムデータの追加 – CustomEvent()

 イベントオブジェクトにデータを追加するには、CustomEvent インターフェイスが存在し、**detail** プロパティを使用してカスタムデータを渡すことができます。
 たとえば、イベントは次のようにして作成することができます。

```js
const event = new CustomEvent("build", { detail: elem.dataset.time });
```

これにより、イベントリスナー内の追加データにアクセスすることができます。

```js
function eventHandler(e) {
  console.log("The time is: " + e.detail);
}
```

### 古い方法

イベントを作成する古いアプローチでは、 Java に触発された API が使用されます。以下に例を示します。

```js
/ イベントの作成
const event = document.createEvent('Event');

// イベントの名前を 'build' と定義する
event.initEvent('build', true, true);

// イベントを待ち受けする
elem.addEventListener('build', function (e) {
  // e.target が elem と一致したとき
}, false);

// 対象が何らかの Element またはその他の EventTarget の場合
elem.dispatchEvent(event);
```

### イベントのバブリング

子要素からイベントを起動させ、祖先要素がそれを、任意でデータも、受け取りたい場合がよくあります。

```html
<form>
  <textarea></textarea>
</form>
```

```js
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");

// 新しいイベントを生成し、バブリングを許可し、 "detail" プロパティに渡したいデータを設定する
const eventAwesome = new CustomEvent("awesome", {
  bubbles: true,
  detail: { text: () => textarea.value },
});

// フォームイベントが "awesome" カスタムイベントを待ち受けし、渡されたものの text() メソッドをコンソールに出力する
form.addEventListener("awesome", (e) => console.log(e.detail.text()));

// ユーザー型の場合、 form 内の textarea は発生させるイベントを起動・処理し、それを開始点として使用する
textarea.addEventListener("input", (e) => e.target.dispatchEvent(eventAwesome));
```

### イベントの動的な生成と処理

要素はまだ作成されていないイベントを待ち受けすることができます。

```html
<form>
  <textarea></textarea>
</form>
```

```js
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");

form.addEventListener("awesome", (e) => console.log(e.detail.text()));

textarea.addEventListener("input", function () {
  // Create and dispatch/trigger an event on the fly
  // Note: Optionally, we've also leveraged the "function expression" (instead of the "arrow function expression") so "this" will represent the element
  this.dispatchEvent(
    new CustomEvent("awesome", {
      bubbles: true,
      detail: { text: () => textarea.value },
    }),
  );
});
```

### 組み込みイベントの起動

この例では、 DOM メソッドを使用してチェックボックスでクリック (プログラムでクリックイベントを生成する) をシミュレートする方法を示します。デモを見る。

```js
function simulateClick() {
  const event = new MouseEvent("click", {
    view: window,
    bubbles: true,
    cancelable: true,
  });
  const cb = document.getElementById("checkbox");
  const cancelled = !cb.dispatchEvent(event);

  if (cancelled) {
    // A handler called preventDefault.
    alert("cancelled");
  } else {
    // None of the handlers called preventDefault.
    alert("not cancelled");
  }
}
```

関連情報
----

* CustomEvent()
* `document.createEvent()`
* `Event.initEvent()`
* `EventTarget.dispatchEvent()`
* `EventTarget.addEventListener()`


イベントの扱い (概要) - イベントリファレンス

イベントの扱い (概要)
============

イベントとは、ブラウザーや OS の環境の変化を知らせる信号で、ブラウザーのウィンドウ内で発行されます。プログラマーは、イベントが発行されたときに実行される*イベントハンドラー*のコードを作成することで、ウェブページが変化に適切に対応できるようになります。

このページでは、イベントとイベントハンドラーの扱い方について、ごく簡単な「覚え書き」を提供しています。初めての方は、イベント入門をお読みください。

イベントでは何ができるのか
-------------

イベントは、そのイベントを発行させる JavaScript オブジェクトのページの中や下に記述されています。例えば、ブラウザーのウィンドウや現在の文書で発生したイベントを確認するには、 `Window` や `Document` のイベントの節を参照してください。

イベントのリファレンスを使用すると、アニメーションやメディアなどの特定の API に対してどの JavaScript オブジェクトがイベントを発行するかを調べることができます。

イベントハンドラーの登録
------------

ハンドラーの登録には、推奨される方法が 2 つあります。イベントハンドラーのコードは、ターゲットとなる要素の対応する *onevent* プロパティに割り当てて、イベントが起動されたときに実行されるようにするか、 `addEventListener()` メソッドを使用して、ハンドラーを要素のリスナーとして登録するかすることができます。いずれの場合も、ハンドラーは `Event` インターフェイス (または派生インターフェイス) に準拠したオブジェクトを受け取ります。主な違いは、イベントリスナーのメソッドを使うと、複数のイベントハンドラーを追加 (または削除) できることです。

**警告:** 第 3 の方法として、 HTML の onevent 属性を使ってイベントハンドラーを設定する方法がありますが、お勧めしません。これはマークアップを膨張させ、可読性を低下させ、デバッグを困難にします。詳しくは、インラインイベントハンドラーを参照してください。

### onevent プロパティの使用

慣習上、イベントを発行する Javascript オブジェクトには、それに対応する "onevent" プロパティ (イベント名の前に "on" を付けて命名) があります。これらのプロパティは、イベントが発行されたときに、関連するハンドラーコードを実行するために呼び出されます。

イベントハンドラーのコードを設定するには、適切な onevent プロパティに代入してください。 1 つの要素のそれぞれのイベントに対して、割り当てることができるイベントハンドラーは 1 つだけです。必要に応じて、同じプロパティに別の関数を代入することで、ハンドラーを置き換えることができます。

以下の例では、 `greet()` 関数を `click` イベントに割り当てるために `onclick` プロパティを使用しています。

```js
const btn = document.querySelector("button");

function greet(event) {
  // print the event object to console
  console.log("greet:", arguments);
}

btn.onclick = greet;
```

なお、イベントハンドラーの第一引数には、イベントを表すオブジェクトが渡されます。このイベントオブジェクトは、 `Event` インターフェースを実装しているか、またはそれを継承しています。

### EventTarget.addEventListener

要素にイベントハンドラーを設定する最も柔軟な方法は、 `EventTarget.addEventListener` メソッドを使用することです。この方法では、複数のリスナーを 1 つの要素に割り当てることができ、必要に応じて (`EventTarget.removeEventListener` を使用して) リスナーを削除することができます。

**メモ:** イベントハンドラーの追加と削除ができることで、例えば、同じボタンで状況によって異なるアクションを実行することができます。また、より複雑なプログラムでは、古い、使われていないイベントハンドラーを整理することで、効率を上げることができます。

以下では、単純な `greet()` 関数をクリックイベントのリスナーまたはイベントハンドラーとして設定する方法を示します (必要に応じて、名前付き関数の代わりにラムダ関数を使用することもできます)。繰り返しますが、イベントは、イベントハンドラーの第一引数として渡されます。

```js
const btn = document.querySelector("button");

function greet(event) {
  // print the event object to console
  console.log("greet:", arguments);
}

btn.addEventListener("click", greet);
```

このメソッドは、イベントのキャプチャおよび削除の制御をするために、追加の引数/オプションを取ることもできます。詳細については、 `EventTarget.addEventListener` のリファレンスページを参照してください。

#### 中止シグナルの使用

イベントリスナーの注目すべき機能は、中止シグナルを使って複数のイベントハンドラーを同時にクリーンアップできることです。

これは、同じ `AbortSignal` を、一緒に削除できるようにしたいすべてのイベントハンドラーの `addEventListener()` 呼び出しに渡すことで行われます。その後、 `AbortSignal` を所有するコントローラーで `abort()` を呼び出すと、そのシグナルで追加されたすべてのイベントハンドラーが削除されます。例えば、 `AbortSignal` で削除できるイベントハンドラーを追加するには、次のようにします。

```js
const controller = new AbortController();

btn.addEventListener(
  "click",
  function (event) {
    // イベントオブジェクトをコンソールに表示
    console.log("greet:", arguments);
  },
  { signal: controller.signal },
); // このハンドラーに AbortSignal を渡す
```

上記のコードで生成したイベントハンドラーは、次のようにして削除することができます。

```js
controller.abort(); // このコントローラーに関連付けられたすべてのイベントハンドラーを削除
```


ホーム画面に追加 - プログレッシブウェブアプリ (PWA)

ホーム画面に追加
========

ホーム画面に追加 (または A2HS と略記) は最近のブラウザーで利用できる機能で、ユーザーがウェブアプリを「インストール」、すなわちお気に入りのウェブアプリケーション (またはウェブサイト) を表すショートカットを自分のホーム画面に追加することができるので、今後はこのショートカットを一回タップすればアクセスできるようになります。このガイドでは、 A2HS の使用方法と、ユーザーがこの機能を利用できるようにするために開発者として行う必要のあることについて説明します。

なぜ A2HS か
---------

A2HS はプログレッシブウェブアプリの思想の一環となるよう考えられています。 — ウェブアプリにネイティブアプリと同等の使い勝手を与えることで、今日のエコシステム競争に参戦できるものです。この部分はホーム画面のアイコンをタップするという簡単な操作でアプリを起動できるものであり、きちんとした独自のウィンドウに表示されます。 A2HS ではこれを実現します。

A2HS に対応しているブラウザー
-----------------

A2HS は、 iOS webview を除いたすべてのモバイルブラウザーが対応しています。また、一部の Chromium ベースのデスクトップブラウザーも対応しています。

Firefox はモバイルでの対応をv58 から行っています。

正確な詳細は caniuse.com を参照してください。

利用方法
----

A2HS を説明するために最小構成のサンプルページを作成しました(デモページはここから, ソースコードは こちらから)。このページ自体に大した機能はありませんが、ページを端末のホーム画面に追加してサービスワーカーのお陰でページをオフラインで使用可能にするために必要なコードが書かれています。このページは何枚かのキツネの写真を表示します。

もし Android 版 Firefox または Android 版 Chrome を使用可能であれば、それを使用してデモに移動してみてください（URL バーは Chrome では上端、 Firefox では下端に表示されます。）。

![URL バーメニューL](/ja/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable/url_bar_menu.png)

 URL バーの横にあるメニューを開きます。
 使用しているのが Chrome であるか、 Android であるかによって、「インストール」または「アプリのインストール」というメニューが表示されます。
 これが、必要な機能を備えているサイトに表示される「ホーム画面に追加」オプションです。

![アプリをインストールするオプション付きメニュー](/ja/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable/menu_install_app.png)

**メモ:** 古いバージョンのブラウザーでは、「ホーム」アイコンの中にプラス (+) アイコンが表示される場合があります。
 これは同じことを行います。

![ホーム画面に追加するアイコン（古いブラウザーで使用するもの）](/ja/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable/add-to-home-screen-icon.png)

オプションを選択すると、アプリケーションをホーム画面に追加する処理が開始されます。

 このプロセスは、ブラウザー、モバイル端末のオペレーティングシステム、さらには機器によって若干異なる場合があります。
 例えば、 Google Pixel 3 で Android 上の Firefox を使用すると、 Pixel ランチャーが表示されます。

![Pixelランチャーでのアプリのインストール](/ja/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable/pixel_launcher_add_app.png)

**メモ:** Chrome のインストールバナーについては、自分自身でウェブインストール体験を指定された方法の記事から、いろいろと調べることができます。

どのブラウザーで使用しているかにかかわらず、ホーム画面に追加することを選ぶと、ネイティブアプリと同じように、短いタイトルとともにアプリが表示されるのがわかります。

![](/ja/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable/a2hs-on-home-screen.png)

このアイコンをタップすると開きますが、全画面アプリとして開き、その周囲のブラウザー UI は表示されません。

アプリを A2HS 対応にするには
-----------------

ウェブアプリを A2HS 対応にするには、次の要件を満たしている必要があります。

* ウェブアプリが HTTPS で配信されていること ― ウェブはいまよりセキュアなほうへ向かっており A2HS を含むモダンなウェブ技術はセキュアな通信の上でのみ動くようになっています。
* 正しくフィールドが記入されたマニフェストファイルが含まれていて、それが HTML の <head> 部分にリンクされていること
* ホーム画面に追加した時に正しく表示されるように適切なアイコンが含まれていること
* Chrome は、追加でアプリがサービスワーカーを登録しておく必要があります (例えば、オフライン時に機能するように)。
### マニフェスト

マニフェストファイルは JSON 形式で書かれ、ウェブアプリ内のどこかに設置される必要があります (置き場所はルートディレクトリにするのがよいです)。またファイルの拡張子は `.webmanifest` にします。ここでは `manifest.webmanifest` といファイル名にしました。このファイルにはウェブアプリについての情報やどのような挙動をするのかについての設定が記されています。

**メモ:** 拡張子`.webmanifest` は W3C のWebAppManifest についてのドキュメントの中の Media type registration の節の中で定義されています。ただ、多くの場合ブラウザーは拡張子 `.json` マニフェストファイルをサポートしています。

A2HS に必要なフィールドは次の通りです。

* `background_color`: いくつかのアプリのコンテキストで使用する背景色を指定します。 A2HS に最も関連するのは、ホーム画面のアプリアイコンをタップして最初にロードを開始したときに表示されるスプラッシュ画面です (現在のところ、これは Chrome でアプリがホーム画面に追加されたときにのみ表示されます)。
* `display`: アプリの表示方法を指定します。独立したアプリ (単なるウェブページではなく) のように見せるには、 `fullscreen` (UI が全く表示されない) や `standalone` (よく似ているが、ステータスバーなどのシステムレベルの UI 要素が表示される場合がある) などの値を選択してください。
* `icons`: アプリをさまざまな場所 (タスク切り替えや肝心のホーム画面) など、で表示する際に使用するブラウザーのアイコンを指定します。今回のデモでは 1 つだけを含めました。
* `name`/`short_name`: これらのフィールドは、異なる場所でアプリを表示する際に表示されるアプリ名を提供します。 `name` はアプリの完全な名前を提供し、 `short_name` は完全な名前を表示するためのスペースが不足している場合に使用される短縮名を提供します。アプリの名前が特に長い場合は、両方を指定することをお勧めします。
* `start_url`: ホーム画面に追加したアプリが起動したときに読み込まれる資産へのパスを指定します。これは、サイトインデックスを指す相対 URL であり、マニフェストの URL からの相対 URL でなければならないことに注意してください。また、 Chrome ではインストールバナーを表示するのに必要ですが、 Firefox でプラス印の付いたホームのアイコンを表示するためは必要ではないことに注意してください。

サンプルアプリのマニフェストは次のようになります。

```json
{
  "background\_color": "purple",
  "description": "Shows random fox pictures. Hey, at least it isn't cats.",
  "display": "fullscreen",
  "icons": [
    {
      "src": "icon/fox-icon.png",
      "sizes": "192x192",
      "type": "image/png"
    }
  ],
  "name": "Awesome fox pictures",
  "short\_name": "Foxes",
  "start\_url": "/pwa-examples/a2hs/index.html"
}
```

### 適切なアイコン

上記のマニフェスト一覧に記載されているように、アプリを使用するために192 x 192 pxのアイコンを記載しています。必要に応じて、さらに多くのサイズを記載することができます。Android は、さまざまな用途に応じて最も適切なサイズを選択します。また、端末が最適なものを使用できるように、異なる種類のアイコンを記載することもできます（例: Chrome はすでに WebP 形式に対応しています）。

各アイコンのオブジェクトの `type` メンバがアイコンの MIME タイプを指定することに注意してください。これにより、ブラウザーはそのアイコンの種類をすばやく読み取り、対応していない場合はそれを無視して別のアイコンに移動することができます。

アイコンのデザイン方法については、他の Android のアイコンと同じ最善の手法に従うべきです（ Google Play icon design specifications を参照）。

### HTML からマニフェストへリンクする

マニフェストの設定を完了するには、アプリケーションのホームページの HTML からマニフェストを参照する必要があります。

```html
<link rel="manifest" href="manifest.webmanifest" />
```

A2HS に対応しているブラウザーは、これによってマニフェストがどこにあるかを把握することができます。

A2HS でできないこと
------------

ホーム画面にアプリを追加しても、それはアプリを簡単にアクセスできるようにするだけで、アプリの資産やデータを機器にダウンロードしたり、アプリをオフラインで利用できるようにしたりするようなことはしないことを覚えておいてください。アプリをオフラインで動作させるには、オフラインで資産を格納するためにサービスワーカー API を使用し、必要に応じて ウェブストレージ や IndexedDB を使用してそのデータを格納するようにしなければなりません。

この例のアプリでは、必要なファイルをすべて格納するためにサービスワーカーを使用しただけです。サービスワーカーは、 `index.js` ファイル内の最後のコードブロックで、サイトに対して登録されます。次に、キャッシュ API を使用してサイトのすべての資産をキャッシュし、 sw.js ファイルのコードを使用してネットワークの代わりにキャッシュからそれらを提供します。

デスクトップでの A2HS
-------------

本来はモバイル OS での使い勝手を向上させるためのものですが、PWA をデスクトッププラットフォームにもインストールする動きが出てきてい ます。

**メモ:** この説明の時点では、以下の機能は新しいバージョンのChromeでのみ対応しています。Windowsでは既定で、 macOS では `#enable-desktop-pwas` フラグの後ろで対応しています。

### インストールボタンの追加

PWA インストール機能をデスクトップでも実現するには、まずインストールボタンをドキュメントに追加する必要があります。デスクトップではモバイル端末とは違い自動的にポップアップなどが出るわけではなくユーザーがトリガーを設定してやる必要があるのです。

```html
<button class="add-button">ホーム画面に追加</button>
```

例えばこんなふうにデザインします。

```css
.add-button {
  position: absolute;
  top: 1px;
  left: 1px;
}
```

### インストールを扱うための JavaScript

`index.js` ファイルの一番下に、インストールを処理するための JavaScript を追加しています。まず最初に、変数 `deferredPrompt` を宣言し（これについては後ほど説明します）、インストールボタンを参照し、最初は `display: none` に設定しています。

```js
let deferredPrompt;
const addBtn = document.querySelector(".add-button");
addBtn.style.display = "none";
```

PWA は A2HS の基準に従うことで、初めてインストールを利用できるようになるため、最初はボタンを非表示にしています。このとき、対応しているブラウザーは `beforeinstallprompt` イベントを発行します。そして、以下のようなハンドラーを使用して、インストールを処理することができます。

```js
window.addEventListener("beforeinstallprompt", (e) => {
  // Chrome 67以前のバージョンでプロンプトが自動的に表示されないようにする
  e.preventDefault();
  // 後で発生させることができるように、イベントを隠しておく。
  deferredPrompt = e;
  // ホーム画面に内側へ追加できることをユーザーに通知する UI の更新
  addBtn.style.display = "block";

  addBtn.addEventListener("click", (e) => {
    // A2HS ボタンを表示するユーザーインターフェイスを非表示にします。
    addBtn.style.display = "none";
    // プロンプトを表示
    deferredPrompt.prompt();
    // ユーザーがプロンプトに応答するのを待つ
    deferredPrompt.userChoice.then((choiceResult) => {
      if (choiceResult.outcome === "accepted") {
        console.log("ユーザーが A2HS プロンプトを受け入れました。");
      } else {
        console.log("ユーザーは A2HS のプロンプトを拒否しました。");
      }
      deferredPrompt = null;
    });
  });
});
```

すなわち、次のようにします。

* `Event.preventDefault()` を呼び出すと、 Chrome 67 以前では自動的にインストールプロンプトを呼び出さなくなります（この動作は Chrome 68 で変更されました）。
* イベントオブジェクトを `deferredPrompt` 変数に格納し、後で実際のインストールを行う際に使用できるようにします。
* ボタンを `display: block` に設定し、ユーザーがクリックできるように UI に表示されるようにします。
* ボタンに `click` ハンドラーを設定します。

クリックハンドラーは以下のステップで構成されています。

* ボタンを `display: none` でもう一度隠します。アプリがインストールされたらもう必要ありません。
* インストールプロンプトを表示するトリガーとして、（`deferredPrompt` に格納された） `beforeinstallprompt` イベントオブジェクトで利用できる `prompt()` メソッドを使用します。
* 再び `beforeinstallprompt` イベントオブジェクトで使用できる `userChoice` プロパティを使用して、ユーザーとプロンプトの対話に応答します。
* もう必要ないので、 `deferredPrompt` を null に設定します。

そこで、ボタンをクリックすると、インストールを促すプロンプトが現れます。

![](/ja/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable/chrome-desktop-a2hs-banner.png)

ユーザーが [インストール] を選択すると、アプリはインストールされ（スタンドアロンのデスクトップアプリとして利用できます）、インストールボタンは表示されなくなります（アプリがすでにインストールされている場合は、 `onbeforeinstallprompt` イベントが発行されなくなります）。アプリを開くと、アプリは自分自身でウィンドウに表示されます。

![](/ja/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable/a2hs-installed-desktop.png)

ユーザーが [キャンセル] を選択すると、アプリの状態はボタンがクリックされる前の状態に戻ります。

**メモ:** この章のコードは多くを How to provide your own in-app install experience (Pete LePage) から引用しました。

関連情報
----

* プログレッシブウェブアプリ
* サービスワーカー API
* ウェブマニフェストリファレンス


プログレッシブウェブアプリの紹介 - プログレッシブウェブアプリ (PWA)

プログレッシブウェブアプリの紹介
================

* Overview: Progressive web apps
* 次のページ

この記事ではプログレッシブウェブアプリ (Progressive Web Apps, PWA) を紹介し、それが何なのか、また普通のウェブアプリよりもどのような利点があるのかを説明します。

プログレッシブウェブアプリとは
---------------

**メモ:** 「プログレッシブウェブアプリ」という用語は、公式または正式な名称ではありません。ウェブ技術だけを使って、柔軟性と適応性のあるアプリケーションを作成するというコンセプトのもと、 Google が当初使用していた略語です。

PWA は数々の特定の技術と、ウェブアプリとネイティブアプリの機能の利点を併せ持った標準パターンを使用して開発されたウェブアプリです。例えば、ウェブアプリはより見つけやすいものです。アクセスするのは、アプリケーションをインストールするよりはるかに簡単で手早く、リンクを通してウェブアプリを共有することもできます。

一方、ネイティブアプリはオペレーティングシステムとより調和するので、ユーザーにもっとシームレスな使い勝手を提供します。ネイティブアプリをインストールするとオフラインで動作し、ユーザーはブラウザーを使ってアプリに移動するのではなく、ホーム画面のアイコンから好きなアプリをタップするだけで簡単にアクセスできます。

PWA によって、ネイティブアプリの利点を引き継いだウェブアプリケーションを作成することができます。

これ新しい概念ではありません。このような考えは、過去にもウェブプラットフォーム上で、様々なアプローチにより何度も繰り返されてきました。プログレッシブエンハンスメントとレスポンシブデザインにより、すでにモバイルフレンドリーなウェブサイトを構築することができます。

しかし、PWA はウェブを素晴らしいものにする既存の機能を一切排除することなく、これらすべてとそれ以上の機能を提供します。

何がアプリを PWA にするのか
----------------

前に述べたように、PWA は単一の技術によって成り立っているわけではありません。PWA とはウェブアプリケーションを構築するための新しい哲学を表しており、いくつかの特定のパターンや API、機能を含みます。一見しただけではそのウェブアプリが PWA かを見極めることはできません。ウェブアプリは、特定の要件を満たしているか、あるいは特定の機能を実装している場合に、PWA と見なされます。例えば、オフラインで動作すること、インストールできること、簡単に同期できること、プッシュ通知を送信することができることなどです。

更に、アプリの完成度をパーセント値で測定するツールもあります (今のところは Lighthouse が最も有名です)。様々な技術的優位性を実装することでアプリをより進化的 (progressive) にすることができ、より高い Lighthouse のスコアを得ることができます。しかし、このスコアは大まかな指標でしかありません。

ウェブアプリが PWA として見なされるために、いくつかの重要な原則があります。

* 発見可能 (Discoverable): コンテンツを検索エンジンで見つけることができる。
* インストール可能 (Installable): アプリを端末のホーム画面に追加できる。
* リンク可能 (Linkable): URL を送るだけでアプリを共有できる。
* ネットワーク非依存 (Network independent): オフラインか、あるいは貧弱なネットワーク環境でも使用できる。
* 進化的 (Progressively enhanced): 古いブラウザーでも基本的な機能は使用でき、最新のブラウザーではすべての機能が使用できる。
* 再エンゲージ可能 (Re-engageable): 新しいコンテンツがあるときには、通知を送ることができる。
* レスポンシブデザイン (Responsively designed): 携帯電話やタブレット、ノートパソコン、テレビ、冷蔵庫など、画面とブラウザーを備える全ての端末で使用できる。
* 安全性 (Secure): アプリからの通信が第三者からの攻撃に対して安全であり、機密情報を保護できる。

これらの機能を提供し、長所をすべて活用することで、ユーザーや顧客にとって魅力的で柔軟性の高いサービスを提供することができます。

### 取り組む価値はありますか？

もちろん！基本的な PWA の機能を実装するのに必要な労力は比較的小さく、得られる便益は膨大です。例をあげましょう。

* サービスワーカーによるキャッシュのおかげで、貴重な帯域幅と時間の節約とともに、アプリがインストールされた後の読み込み時間が短縮されます。 PWA は (2 回目のアクセスから) ほぼ瞬時にローディングが行われます。
* アプリの更新があると、変更されたコンテンツだけを更新することができます。一方、ネイティブアプリでは、わずかな変更でもユーザーはアプリ全体をダウンロードし直さなければなりません。
* ネイティブプラットフォームとよく統合されたルックアンドフィール。例えばホーム画面のアプリアイコンや、全画面で動作するアプリなど。
* システム通知やプッシュメッセージによるユーザーの再エンゲージ。これはエンゲージユーザーやコンバージョン率の向上に繋がる。

PWA のアプローチは挑戦する十分な価値があります。あなたのアプリでそれがどう動くのか、ぜひ自身で確認してみてください。

ウェブアプリケーションの利点
--------------

完全に機能するプログレッシブウェブアプリケーションは、以下のすべての利点をユーザーに提供する必要があります。

### 発見可能性

最終的な目的は、ウェブアプリが検索エンジンでより適切に表現され、公開されやすく、カタログ化とランク付けされ、ブラウザーにメタデータを使用してそれらに特別な機能を提供することです。

一部の機能は、Open Graph のような独自の技術によって特定のウェブベースのプラットフォームですでにできるようになっています。これは HTML の `<head>` ブロック内で `<meta>` タグを使って同様のメタデータを指定するフォーマットを提供しています。

ここで関連するウェブ標準はウェブアプリマニフェスト（Web app manifest）です。 これは、名前、アイコン、スプラッシュ画面、テーマカラーなどのアプリの機能を JSON 形式のマニフェストファイルで定義します。 これは、アプリ一覧や端末のホーム画面などの場面で使用するためのものです。

### インストール可能性

ウェブアプリの使い勝手の中心となるのは、ユーザーがホーム画面にアプリのアイコンを表示し、タップしてアプリを開くことができるネイティブコンテナーであり、基盤となるプラットフォームとうまく統合されていることです。

最近のウェブアプリは、ウェブアプリマニフェストに設定されたプロパティや、最近のスマートフォンブラウザーで利用できるウェブアプリのインストール (en-US)と呼ばれる機能によって、このようなネイティブアプリの感覚を持つことができます。

### リンク可能性

ウェブの最も強力な機能の 1 つは、特定の URL でアプリにリンクできることです。アプリストアは不要で、複雑なインストールプロセスも不要です。これは今までもそうでした。

### ネットワーク非依存性

最新のウェブアプリケーションは、ネットワークの信頼性が低い、あるいは存在しない場合でも動作します。ネットワーク非依存性の基本的な考え方は、以下の通りです。

* ネットワークが利用できない場合でも、サイトを再訪してそのコンテンツを取得できる。
* ユーザーが過去に一度でもアクセスしたことのあるコンテンツであれば、接続性が悪い状況でも閲覧できる。
* 接続がない状況で、ユーザーに表示するものを制御することができます。

これは、ページリクエストを制御するサービスワーカー (オフラインでの保存など)、ネットワークリクエストに対するレスポンスをオフラインで保存する Cache API (サイトの資産を保存するのにとても便利)、アプリケーションデータをオフラインで保存するウェブストレージや IndexedDB などのクライアントサイドのデータストレージ技術など、さまざまな技術を組み合わせて実現されています。

### プログレッシブエンハンスメントの対応

最近のウェブアプリは、十分な機能を備えたブラウザーでは優れた使い勝手を、機能の劣るブラウザーでは (見劣りするものの) 許容できる使い勝手を提供するように開発することができます。私たちは、プログレッシブエンハンスメントなどのベストプラクティスを用いて、何年も前からこれを行ってきました。プログレッシブエンハンスメントを使用することで、 PWA はクロスブラウザーに対応します。つまり開発者は、 PWA の一部の機能や技術の実装が、ブラウザーの実装ごとに異なることを考慮する必要があります。

### 再エンゲージ可能性

ネイティブプラットフォームの大きな利点は、ユーザーがアプリを見ていない時や端末を使用していない時でも、アップデートや新しいコンテンツによってユーザーを簡単に再エンゲージできることです。最近のウェブアプリでは、ページを制御するサービスワーカー、サーバーからサービスワーカーを介してアプリに直接アップデートを送信する Web Push API、システム通知を生成する Notifications API などの新しい技術を使用することで、このようなことが可能になっていますが、ユーザーがウェブブラウザーを積極的に使用していないときにも、ユーザーの関心を引くことができます。

### レスポンシブ性

レスポンシブウェブアプリでは、メディアクエリーやビューポートなどの技術を用いて、デスクトップ、モバイル、タブレットなど、あらゆるフォームファクターに対応する UI を実現しています。

### 安全性

HTTPS を利用し、セキュリティを考慮してアプリを開発していれば、ウェブプラットフォームは、コンテンツが改ざんされていないことを確認すると同時に、盗み見されることを防ぐ安全な配信メカニズムを提供します。

また、アプリの URL がサイトのドメインと一致するため、ユーザーは正しいアプリをインストールしているかどうかを簡単に確認することができます。これは、アプリストアのアプリとは大きく異なります。アプリストアには似たような名前のアプリがいくつもあり、中には自分のサイトをベースにしたものもあるため、混乱を招くだけです。ウェブアプリは、そのような混乱を解消し、ユーザーに最高の使い勝手を提供します。

ブラウザーの対応
--------

前述のように、PWA は単一の API に依存するのではなく、さまざまなテクノロジーを使用して、可能な限り最高のウェブの操作性を提供するという目標を達成します。

PWA に必要な重要な要素は、サービスワーカーのサポートです。ありがたいことに、サービスワーカーは現在、デスクトップとモバイルのすべての主要なブラウザーでサポートされています。

ウェブアプリマニフェストやプッシュ通知、お知らせ、ホーム画面に追加などの他の機能も幅広く対応されています。現在、Safari では、ウェブアプリマニフェストとホーム画面に追加の対応が制限されており、ウェブプッシュ通知には対応していません。ただし、他の主要なブラウザーはこれらすべての機能に対応しています。

特に、プログレッシブエンハンスメントのルールに従うべきです。つまり、利用可能な場合はアプリの外観や実用性を向上させる技術を使用し、それらの機能が利用できない場合はアプリの基本的な機能を提供します。信頼性の高いウェブサイトを優れたパフォーマンスで提供することは、これらの機能強化を使用することの結果であり、これは、より良い慣行に従ったウェブアプリを構築することを意味します。このようにして、誰もがアプリを使用できるようになりますが、モダンブラウザーを使用している人は、 PWA 機能の恩恵をさらに受けることができます。

アプリケーションの例
----------

このシリーズの記事では、 js13kGames 2017 競技会の *A-Frame* カテゴリーに提出されたゲームに関する情報をリストする、非常にシンプルなウェブサイトのソースコードを調べます。ウェブサイトの実際のコンテンツについて考える必要はありません。主なポイントは、自分のプロジェクトで PWA 機能を使用する方法を学ぶことです。

オンラインでは mdn.github.io/pwa-examples/js13kpwa (ソースコードも参照 ) で見つけることができます。これについては、次のいくつかの記事で詳しく説明します。

それでは、このシリーズの第 2 部に移り、サンプルアプリの構造を見ていきましょう。

* Overview: Progressive web apps
* 次のページ


PWA をインストール可能にするには - プログレッシブウェブアプリ (PWA)

PWA をインストール可能にするには
==================

* 前のページ
* Overview: Progressive web apps
* 次のページ

前回の記事では、サンプルアプリケーション js13kPWA がサービスワーカーによってオフラインで動作する方法を見てきましたが、さらに、対応しているモバイルブラウザーやデスクトップブラウザーでは、ウェブアプリをユーザーがインストールできるようにすることができます。インストールされたウェブアプリは、ネイティブアプリと同様にユーザーが起動することができます。 この記事では、ウェブアプリマニフェストと「ホーム画面に追加」と呼ばれる機能を使用して、これを実現する方法を説明します。

これらの技術により、ユーザーはブラウザーを開いてからブックマークを使ってサイトに移動したり、 URL を入力したりするのではなく、アプリを端末のホーム画面から直接起動することができます。ウェブアプリは、第一級市民としてネイティブアプリケーションの隣に座ることができます。さらに、アプリを全画面またはスタンドアロン モードで起動するように指定できるため、既定ののブラウザーのユーザーインターフェイスが削除され、よりシームレスでネイティブアプリに近い感覚が得られます。

要求事項
----

ウェブサイトをインストール可能にするには、以下のものが必要になります。

* 正しくフィールドが入力されたウェブマニフェスト
* 安全な (HTTPS) ドメインから提供されるウェブサイト
* 端末上のアプリを表すアイコン
* アプリをオフラインで動作させるために登録されたservice worker (現時点では Android の Chrome にのみ必要です)

**メモ:** 現在、サービスワーカーが必要なのは、 Chrome, Edge, Samsung Internet などの Chromium ベースのブラウザーのみです。Firefox を使ってアプリを開発する場合は、 Chromium ベースのブラウザーと互換性を持たせるためにサービスワーカーが必要になるので注意が必要です。

### マニフェストファイル

重要な要素はウェブマニフェストファイルです。 このファイルには、ウェブサイトに関するすべての情報が JSON 形式でリストされます。

通常、ウェブアプリのルートフォルダーに存在します。これには、アプリのタイトル、 OS 上でアプリを表現するために使用できる様々なサイズのアイコンへのパス (ホーム画面上のアイコン、スタートメニューの項目、デスクトップ上のアイコンなど)、読み込み中画面やスプラッシュ画面で使用する背景色などの有用な情報が含まれています。この情報は、ブラウザーがインストール処理中にウェブアプリを適切に表示したり、モバイル端末のホーム画面などの端末のアプリ起動インターフェイス内で表示したりするために必要です。

js13kPWA ウェブアプリの `js13kpwa.webmanifest` ファイルは、 `index.html` ファイルの `<head>` ブロックに次のコード行を使用して含まれています。

```html
<link rel="manifest" href="js13kpwa.webmanifest" />
```

**メモ:** 過去にマニフェストに使用されてきた一般的な拡張機能がいくつかあります。 `manifest.webapp` は Firefox OS アプリのマニフェストで一般的でしたが、多くの場合、コンテンツは JSON 構造で編成されているためウェブマニフェストには `manifest.json` を使用します。 しかし、`.webmanifest` ファイル形式は W3C マニフェスト仕様書 (英語) で明示的に言及されており、ここでは使用するのはこれです。

ファイルの内容は次のようになります。

```json
{
  "name": "js13kGames Progressive Web App",
  "short\_name": "js13kPWA",
  "description": "Progressive Web App that lists games submitted to the A-Frame category in the js13kGames 2017 competition.",
  "icons": [
    {
      "src": "icons/icon-32.png",
      "sizes": "32x32",
      "type": "image/png"
    },
    // ...
    {
      "src": "icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "start\_url": "/pwa-examples/js13kpwa/index.html",
  "display": "fullscreen",
  "theme\_color": "#B12A34",
  "background\_color": "#B12A34"
}
```

ほとんどのフィールドは一目瞭然ですが、念のため、以下のものと同じです。

* `name`: ウェブアプリの正式な名前。
* `short_name`: ホーム画面に表示する省略した名前。
* `description`: アプリが何をするのかを説明する一つ二つの文章。
* `icons`: 一連のアイコン情報 — ソース URL、サイズ、種類。 ユーザーの端末に最適なものが選択されるように、少なくともいくつか含めるようにしてください。
* `start_url`: アプリの起動時に起動する index 文書。
* `display`: アプリの表示方法 — `fullscreen` (全画面), `standalone` (スタンドアロン), `minimal-ui` , `browser` (ブラウザー) のいずれかです。
* `theme_color`: テーマカラー — オペレーティングシステムで使用される UI の基本色です 。
* `background_color`: アプリの既定の背景色、インストール中およびスプラッシュ画面で使用します。

最小限のウェブマニフェストには、少なくとも `name` と、1 つ以上のアイコンが定義された `icons` フィールドがなければなりません。アイコンには、少なくとも `src`, `size`, and `type` がなければなりません。それ以外はすべてオプションですが、`description`, `short_name`, `start_url` フィールドは推奨されます。上記のフィールド以外にも使用できるフィールドがあります。 - 詳細については、必ずウェブアプリマニフェストリファレンスを確認してください。

ホーム画面に追加
--------

「ホーム画面に追加」（Add to home screen、略して a2hs）は、モバイルブラウザーによって実装され、アプリのウェブマニフェストにある情報を取得して、それらを使用して端末のホーム画面上のアプリをアイコンと名前で表す機能です。 これは、上記のように、アプリが必要な要件をすべて満たしている場合にのみ機能します。

ユーザーがサポートしているモバイルブラウザーで PWA にアクセスすると、アプリを PWA としてインストールすることが可能であることを示す通知 (バナーやダイアログボックスなど) が表示されます。

![js13kPWA のホーム画面に追加のポップアップ。](/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-icon.png)

ユーザーがインストールを実行する意志を示したら、インストールバナーが表示されます。 そのバナーは、マニフェストファイルからの情報に基づいて、ブラウザーによって自動的に作成されます。例えば、プロンプトにはアプリの名前とアイコンが含まれています。

![js13kPWA のインストールバナー。](/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-banner.png)

ユーザーがボタンをクリックすると、アプリがどのように表示されるかを示し、間違いなくアプリを追加するかどうかをユーザーに選択させる最後のステップがあります。

![js13kPWA のホーム画面に追加のポップアップ。](/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-add.png)

確認すると、アプリがホーム画面にインストールされます。

![](/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-installed.png)

これでユーザーは、端末上の他のアプリケーションと同じようにウェブアプリを起動して使用することができるようになりました。端末やオペレーティングシステムによっては、ウェブアプリのアイコンにウェブアプリであることを示す小さなアイコンが付けられている場合があります。例えば、上のスクリーンショットでは、アプリには小さな Firefox のアイコンが付いており、 Firefox ランタイムを使用するウェブアプリであることを示しています。

### スプラッシュ画面

一部のブラウザーでは、マニフェストの情報からスプラッシュ画面も生成されます。 これは、 PWA が起動され読み込まれている間に表示されます。

![](/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs/js13kpwa-splash.png)

この画面の作成には、アイコンとテーマカラーと背景色が使用されます。

まとめ
---

この記事では、適切に設定されたウェブマニフェストで PWA をインストール可能にする方法と、その後でブラウザーの「ホーム画面に追加」機能を使って PWA をインストールする方法について学びました。

a2hs の詳細については、必ずホーム画面に追加のガイドをお読みください。 ブラウザーのサポートは現在、Android の Firefox 58 以降、Mobile Chrome および Android Webview 31 以降、および Android の Opera 32 以降に制限されていますが、近い将来に改善されるはずです。

それでは、PWA パズルの最後のピース、プッシュ通知を使用してユーザーとアナウンスを共有し、ユーザーがアプリに再び参加できるようにする方法に移りましょう。

* 前のページ
* Overview: Progressive web apps
* 次のページ


プログレッシブ読み込み - プログレッシブウェブアプリ (PWA)

プログレッシブ読み込み
===========

* 前のページ
* Overview: Progressive web apps

前回の記事では、js13kPWA の例をプログレッシブウェブアプリケーションにするのに役立つ API について説明しました — サービスワーカー、ウェブマニフェスト、通知、およびプッシュです。 この記事では、リソースを徐々に読み込せて、アプリのパフォーマンスをさらに向上させます。

First meaningful paint — 最初の意味のあるペイント
-------------------------------------

できるだけ早く意味のあるものをユーザーに提供することが重要です — ページが読み込まれるのを待つ時間が長いほど、すべてが完了するのを待つ前にユーザーが離れる可能性が大きくなります。 少なくとも見たいページの基本的なビューだけでなく、最終的により多くのコンテンツが読み込まれる場所にプレースホルダーを表示することもできるはずです。

これはプログレッシブ読み込み (progressive loading) によっても達成できます — 遅延読み込み (Lazy loading) としても知られています。 これは、できるだけ多くのリソース (HTML、CSS、JavaScript) の読み込みを遅らせること、そして最初のエクスペリエンスに本当に必要なものだけをすぐに読み込むことです。

バンドリングと分割
---------

多くの訪問者はウェブサイトのすべての単一ページを通過するわけではありません、それでも通常のアプローチは持っているすべての機能を一つの大きなファイルに束ねることです。 `bundle.js` ファイルは数メガバイトになる可能性があり、単一の `style.css` の束には、基本的な CSS 構造定義から、（モバイル、タブレット、デスクトップ、印刷専用など）サイトのすべてのバージョンで可能なすべてのスタイルまですべてを含めることができます。

すべての情報をたくさんの小さなファイルではなく 1 つのファイルとして読み込むほうが速いのですが、最初にユーザーがすべてを必要としていない場合は、重要なものだけを読み込み、必要に応じて他のリソースを管理できます。

レンダリングをブロックするリソース
-----------------

バンドリングは問題です — ブラウザーはレンダリングされた結果を画面に表示する前に、HTML、CSS、および JavaScript を読み込む必要があるためです。 最初のウェブサイトへのアクセスから読み込みが完了するまでの数秒間に、ユーザーは空白のページを見ますが、これは悪いエクスペリエンスです。

これを修正するために、例えば、JavaScript ファイルに次のように `defer` を追加することができます。

```html
<script src="app.js" defer></script>
```

それらは文書自体が解析された*後*にダウンロードされて実行されるので、それは HTML 構造のレンダリングをブロックしません。 CSS ファイルを分割して次のようにメディア種別を追加することもできます。

```html
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="print.css" media="print" />
```

これは、条件が満たされた場合にのみそれらを読み込むようブラウザーに指示します。

js13kPWA デモアプリでは、CSS はそれらをどのように読み込むかに関して特別な規則なしで単一のファイルにすべてを残すのに十分に単純です。 さらに進んで、`style.css` から `index.html` の `<head>` 内の `<style>` タグにすべてを移動することもできます — これによりパフォーマンスがさらに向上しますが、例を読みやすくするために、このアプローチもスキップします。

画像
--

JavaScript と CSS 以外にも、ウェブサイトには多くの画像が含まれているでしょう。 HTML に `<img>` 要素を含めると、最初にウェブサイトにアクセスしたときに、参照されているすべての画像が取得されてダウンロードされます。 サイトの準備が整ったことをアナウンスする前にダウンロードするメガバイトの画像データを持っているのは珍しいことではありませんが、これもまたパフォーマンスに対する悪い認識を生み出します。 サイトを閲覧する最初の段階で、可能な限り最高の品質のすべての画像を必要とするわけではありません。

これは最適化することができます。 まず第一に、TinyPNG に似たツールやサービスを使うべきで、それはあまり品質を変えずに画像のファイルサイズを減らすでしょう。 その点を過ぎていれば、JavaScript を使って画像の読み込みを最適化することを考え始めることができます。 以下で説明します。

### プレースホルダー画像

`<img>` 要素の `src` 属性で参照されるゲームのすべてのスクリーンショットを自動的にダウンロードするようにする代わりに、JavaScript で選択的に実行できます。 js13kPWA アプリは代わりにプレースホルダー画像を使用し、これは小さくて軽量です。 一方、ターゲット画像への最終パスは次のように `data-src` 属性に格納されます。

```html
<img src="data/img/placeholder.png" data-src="data/img/SLUG.jpg" alt="NAME" />
```

これらの画像は、サイトが HTML 構造の構築を完了した*後*に JavaScript で読み込まれます。 プレースホルダー画像は元の画像と同じ方法で拡大縮小されるため、同じスペースを占有し、画像の読み込み時にレイアウトが再描画されることはありません。

### JavaScript による読み込み

`app.js` ファイルは `data-src` 属性を次のように処理します。

```js
let imagesToLoad = document.querySelectorAll("img[data-src]");
const loadImages = (image) => {
  image.setAttribute("src", image.getAttribute("data-src"));
  image.onload = () => {
    image.removeAttribute("data-src");
  };
};
```

`imagesToLoad` 変数にはすべての画像への参照が含まれ、`loadImages` 関数はパスを `data-src` から `src` に移動します。 各画像が実際に読み込まれると、もう必要ではなくなったので、`data-src` 属性を削除します。 それから次のように各画像をループして読み込みます。

```js
imagesToLoad.forEach((img) => {
  loadImages(img);
});
```

### CSS でのぼかし

プロセス全体を視覚的により魅力的にするために、プレースホルダーは CSS で、ぼかしています。

![js13kPWA アプリのプレースホルダー画像のスクリーンショット](/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Loading/js13kpwa-placeholders.png)

最初にぼかしを付けて画像をレンダリングするので、シャープな画像に遷移することができます。

```css
article img[data-src] {
  filter: blur(0.2em);
}

article img {
  filter: blur(0em);
  transition: filter 0.5s;
}
```

これにより、0.5 秒以内にぼかし効果が取り除かれます。 これは、「読み込み」効果としては十分に効果的です。

オンデマンドで読み込む
-----------

上のセクションで説明した画像読み込みメカニズムは問題なく動作します — HTML 構造をレンダリングした後に画像を読み込むし、その過程で素晴らしい遷移効果を適用します。 問題はユーザーがページを読み込んでも最初の 2 つか 3 つしか見えないにもかかわらず、まだ*すべて*の画像を一度に読み込むことです。

この問題は新しい Intersection Observer API で解決できます — これを使用すると、ビューポートに表示されたときにのみ画像が読み込まれるようになります。

### Intersection Observer

これは、以前に動作していた例に対するプログレッシブエンハンスメントです — Intersection Observer（交差監視）は、ユーザーが下にスクロールしたときにのみターゲット画像を読み込んで、ビューポートに表示させるようにします。

関連するコードは次のようになります。

```js
if ("IntersectionObserver" in window) {
  const observer = new IntersectionObserver((items, observer) => {
    items.forEach((item) => {
      if (item.isIntersecting) {
        loadImages(item.target);
        observer.unobserve(item.target);
      }
    });
  });
  imagesToLoad.forEach((img) => {
    observer.observe(img);
  });
} else {
  imagesToLoad.forEach((img) => {
    loadImages(img);
  });
}
```

`IntersectionObserver` オブジェクトがサポートされている場合、アプリはその新しいインスタンスを作成します。 パラメータとして渡される関数は、1 つ以上の `items` が `observer` と交差している（つまり、ビューポート内に表示されている）場合を処理します。 それぞれの場合を繰り返してそれに応じて反応することができます — 画像が見えるときは、正しい画像を読み込み、監視する必要がなくなるので監視を中止します。

プログレッシブエンハンスメントについての前述の説明をもう一度繰り返しましょう。 このコードは、Intersection Observer がサポートされているかどうかにかかわらずアプリが機能するように作成されています。 されていない場合は、先ほど説明したより基本的な方法を使用して画像を読み込みます。

改良点
---

読み込み時間を最適化するには多くの方法があり、この例ではそのうちの 1 つのアプローチのみを検討していることを忘れないでください。 JavaScript を使わずに動作させることでアプリをより安全なものにすることができます — `<noscript>` を使用して既に割り当てられた最後の `src` で画像を表示するか、`<a>` 要素でターゲット画像を指す `<img>` タグをラップすることでユーザーは必要に応じてクリックしてアクセスできます。

アプリ自体は JavaScript に依存しているので、これを行いません — それがないと、ゲームのリストが読み込まれず、サービスワーカーのコードも実行されません。

画像だけでなく、詳しい説明とリンクからなる完全な項目を読み込むように読み込み処理を書き直すことができます。 これは無限スクロールのように機能します — ユーザーがページを下にスクロールしたときにだけリストの項目を読み込みます。 そうすれば、初期の HTML 構造は最小限になり、読み込み時間はさらに短くなり、パフォーマンス上の利点もさらに大きくなります。

まとめ
---

最初に読み込むファイルが少ない、モジュールに分割される小さいファイル、プレースホルダーを使用する、さらにオンデマンドでより多くのコンテンツを読み込む — これは初期読み込み時間を短縮するのに役立ち、アプリ作成者にメリットをもたらし、ユーザーにスムーズなエクスペリエンスを提供します。

プログレッシブエンハンスメントのアプローチを忘れないでください — デバイスやプラットフォームに関係なく使用可能な製品を提供しますが、最新のブラウザーを使用しているユーザーにはエクスペリエンスを豊かなものにするようにしてください。

最終的な考え
------

このチュートリアルのシリーズではこれですべてです — js13kPWA サンプルアプリのソースコードを調べて、紹介、PWA の構造、サービスワーカーでのオフライン可用性、インストール可能な PWA、そして最後に通知など、プログレッシブウェブアプリ機能の使用方法について学びました。 また、サービスワーカークックブック（英語）の助けを借りてプッシュを説明しました。 そしてこの記事では、Intersection Observer API を利用した興味深い例を含めて、プログレッシブ読み込みの概念を調べました。

コードを試したり、PWA 機能を使用して既存のアプリを拡張したり、まったく新しいものを自分で作成したりしてください。 PWA は通常のウェブアプリよりも大きな利点をもたらします。

* 前のページ
* Overview: Progressive web apps


プログレッシブウェブアプリの構造 - プログレッシブウェブアプリ (PWA)

プログレッシブウェブアプリの構造
================

* 前のページ
* Overview: Progressive web apps
* 次のページ

PWA の背後にある理論が分かったところで、推奨されるアプリの構造を見てみましょう。まず、 js13kPWA アプリの分析、それがなぜそのように構築されているのか、それがもたらす利点について説明します。

アプリのアーキテクチャ
-----------

ウェブサイトをレンダリングするには、サーバー上とクライアント上の 2 つのアプローチがあります。どちらにも長所と短所があり、2 つのアプローチをある程度組み合わせることができます。

* サーバー側レンダリング (Server-side rendering、SSR) は、ウェブサイトがサーバー上でレンダリングされるという意味で、初回の読み込みは速くなりますが、ページ間で移動すると新しい HTML コンテンツをダウンロードする必要があります。これはブラウザーが変わってもうまく動作しますが、ページ間で移動する時間が不利であり、したがって一般的にパフォーマンスが悪くなります。 — ページを読み込むごとに、サーバーへの新しい往復が必要になるからです。
* クライアント側レンダリング (Client-side rendering、CSR) を使用すると、ウェブサイトがさまざまなページに移動したときにブラウザー内でほぼ瞬時に更新できますが、初期ダウンロード数が増え、最初はクライアントで余分なレンダリングが必要になります。 ウェブサイトは最初の訪問では遅くなりますが、その後の訪問ではずっと速くなります。

SSR と CSR を組み合わせることで最良の結果が得られます — ウェブサイトをサーバー上にレンダリングし、そのコンテンツをキャッシュしてから、必要に応じてクライアント側でレンダリングを更新することができます。 SSR のおかげで最初のページの読み込みは速く、クライアントは変更された部分だけでページを再レンダリングできるため、ページ間のナビゲーションはスムーズです。

PWA は好きなアプローチで構築できますが、他のものよりもうまく機能するものもあります。 最も人気のあるアプローチは、 SSR と CSR をまさに上記の方法で組み合わせた「アプリシェル」の概念です。 さらに、今後の記事で詳細に説明し、サンプルアプリで使用する「オフライン優先」の方法論に従います。 Streams API に関する新しいアプローチもありますが、これについては後で簡単に説明します。

アプリシェル
------

アプリシェル (App shell) の概念は、最小限のユーザーインターフェイスをできるだけ早く読み込んでからキャッシュすること関係しています。 それで、アプリのすべてのコンテンツを読み込むことで、その後のアクセスでオフラインで利用できるようにします。 こうすることで、次回デバイスからアプリにアクセスしたときに、 UI がすぐにキャッシュから読み込まれ、 (まだキャッシュにない場合) 新しいコンテンツがサーバーから要求されます。

この構造は高速であり、ローディングスピナーや空白のページではなく、ユーザーが即座に「何か」を見たときにも高速に感じられます。 ネットワーク接続が利用できない場合は、ウェブサイトにオフラインでアクセスすることもできます。

サーバーから要求される内容とキャッシュから取得される内容をサービスワーカーで制御できます。 詳細は次の記事で説明します — ここでは構造自体に焦点を当てます。

### なぜそれを使うべきか？

このアーキテクチャにより、ウェブサイトはすべての PWA 機能を最大限に活用できます — つまり、アプリシェルをキャッシュし、パフォーマンスを大幅に向上させるように動的コンテンツを管理します。 基本的なシェルに加えて、ホーム画面への追加やプッシュ通知などの他の機能を追加でき、ユーザーのブラウザーでサポートされていない場合でも、アプリは正常に動作することがわかっているので安全です — これがプログレッシブエンハンスメントの美しさです。

ウェブサイトは、ウェブのすべての利点を維持しながら、即時の対話と堅実なパフォーマンスを備えたネイティブアプリのように感じられます。

### 設計によりリンク可能、プログレッシブ、レスポンシブであること

PWA の利点を覚えておき、アプリケーションを設計するときには、それらを念頭に置いておくことが重要です。 アプリシェルのアプローチにより、ウェブサイトは次のようになります。

* リンク可能: ネイティブアプリのように動作しますが、それでもウェブサイトです — ページ内のリンクをクリックして、共有したい場合は他の人に URL を送信できます。
* プログレッシブ: 「古き良き基本的なウェブサイト」から始めて、ブラウザーで利用できるかどうかを検出し、サポートが利用できない場合に発生するエラーを適切に処理しながら、新機能を徐々に追加します。 例えば、サービスワーカーの助けを借りたオフラインモードは、ウェブサイトのエクスペリエンスを向上させるための特別な特徴ですが、それがなくても完全に使用可能です。
* レスポンシブ: レスポンシブウェブデザイン (Responsive web design) はプログレッシブウェブアプリにも適用され、どちらも主にモバイルデバイス用です。 ブラウザーを搭載したデバイスは数多くあります — ビューポートメタタグ、CSS メディアクエリ、フレックスボックス、CSS グリッドなどの技術を使用して、さまざまな画面サイズ、ビューポート、ピクセル密度で機能するようにウェブサイトを準備することが重要です。
異なるコンセプト: ストリーム
---------------

Streams API を使用すると、サーバー側またはクライアント側のレンダリングに対するまったく異なるアプローチを実現できます。 サービスワーカーからの少しの助けで、ストリームはコンテンツを解析する方法を大いに改善することができます。

アプリシェルのモデルでは、ウェブサイトがレンダリングを開始する前にすべてのリソースが利用可能である必要があります。 HTML とは異なり、ブラウザーが実際にデータを既にストリーミング (読み込みながら再生) しているので、いつウェブサイトに要素が読み込まれてレンダリングされるかを見ることができます。 ただし、 JavaScript を「動作可能」にするには、 JavaScript を完全にダウンロードする必要があります。

Streams API を使用すると、開発者はサーバーからのデータストリーミングに直接アクセスできます — データに操作を実行する場合 (例えば、動画にフィルタを追加する場合など) は、すべてがダウンロードされて BLOB (またはその他) に変換されるのを待つ必要はもうありません — すぐに始めることができます。 それは、きめ細かい制御を提供します — ストリームを開始したり、別のストリームとチェーンしたり、キャンセルしたり、エラーをチェックしたりすることができます。

理論的には、ストリーミングはより優れたモデルですが、より複雑でもあり、この記事の執筆時点 (2018 年 3 月) では Streams API はまだ開発中であり、主要ブラウザーのいずれでもまだ完全には利用できません。 それが利用可能になると、それはコンテンツを提供する最も速い方法になるでしょう — パフォーマンスの面で利点は巨大になるでしょう。

実用的な例や詳細については、Streams API の資料を参照してください。

サンプルアプリの構造
----------

js13kPWA ウェブサイトの構造は非常に単純です。単一の HTML ファイル (index.html) と基本的な CSS のスタイル付け (style.css)、いくつかの画像、スクリプト、およびフォントで構成されています。 フォルダー構造は次のようになります。

![js13kPWA のフォルダー構成](/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames/App_structure/js13kpwa-directory.png)

### HTML

HTML の観点から見ると、アプリシェルは content セクション以外のすべてのものです。

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>js13kGames A-Frame entries</title>
    <meta
 name="description"
 content="A list of A-Frame entries submitted to the js13kGames 2017 competition, used as an example for the MDN articles about Progressive Web Apps." />
    <meta name="author" content="end3r" />
    <meta name="theme-color" content="#B12A34" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta property="og:image" content="icons/icon-512.png" />
    <link rel="shortcut icon" href="favicon.ico" />
    <link rel="stylesheet" href="style.css" />
    <link rel="manifest" href="js13kpwa.webmanifest" />
    <script src="data/games.js" defer></script>
    <script src="app.js" defer></script>
  </head>
  <body>
    <header>
      <p>
        <a class="logo" href="http://js13kgames.com"
 ><img src="img/js13kgames.png" alt="js13kGames"
 /></a>
      </p>
    </header>
    <main>
      <h1>js13kGames A-Frame entries</h1>
      <p class="description">
        List of games submitted to the
        <a href="http://js13kgames.com/aframe">A-Frame category</a> in the
        <a href="http://2017.js13kgames.com">js13kGames 2017</a> competition.
        You can
        <a href="https://github.com/mdn/pwa-examples/blob/master/js13kpwa"
 >fork js13kPWA on GitHub</a
 >
        to check its source code.
      </p>
      <button id="notifications">Request dummy notifications</button>
      <section id="content">// コンテンツはここに動的に挿入されます</section>
    </main>
    <footer>
      <p>
        © js13kGames 2012-2018, created and maintained by
        <a href="http://end3r.com">Andrzej Mazur</a> from
        <a href="http://enclavegames.com">Enclave Games</a>.
      </p>
    </footer>
  </body>
</html>
```

`<head>` セクションには、タイトル、説明、 CSS へのリンク、ウェブマニフェスト、ゲームコンテンツの JS ファイル、および `app.js` (ここで、JavaScript アプリが初期化されます) などの基本的な情報が含まれています。 `<body>` は、`<header>` (リンクした画像を含む)、`<main>` ページ (タイトル、説明、コンテンツの場所)、および `<footer>` (著作権およびリンク) に分割されています。

アプリの唯一の仕事は、 js13kGames 2017 コンペティションからすべての A-Frame エントリをリストすることです。 ご覧のとおり、これはごく普通の 1 ページのウェブサイトです — 重要なのは、実際の PWA 機能の実装に集中できるように、簡単なものを用意することです。

### CSS

CSS も可能な限りわかりやすくなっています。 つまり、 `@font-face` を使用してカスタムフォントを読み込んで使用し、さらに HTML 要素の単純なスタイルを適用します。 全体的なアプローチは、デザインをモバイルデバイス (レスポンシブウェブデザインのアプローチ) とデスクトップデバイスの両方で見栄えよくすることです。

### メインアプリの JavaScript

`app.js` ファイルは、次の記事で詳しく調べることをいくつか行います。 まず最初に、次のテンプレートに基づいてコンテンツを生成します。

```js
var template =
  "<article>\n\
 <img src='data/img/SLUG.jpg' alt='NAME'>\n\
 <h3>#POS. NAME</h3>\n\
 <ul>\n\
 <li><span>Author:</span> <strong>AUTHOR</strong></li>\n\
 <li><span>Twitter:</span> <a href='https://twitter.com/TWITTER'>@TWITTER</a></li>\n\
 <li><span>Website:</span> <a href='http://WEBSITE/'>WEBSITE</a></li>\n\
 <li><span>GitHub:</span> <a href='https://GITHUB'>GITHUB</a></li>\n\
 <li><span>More:</span> <a href='http://js13kgames.com/entries/SLUG'>js13kgames.com/entries/SLUG</a></li>\n\
 </ul>\n\
</article>";
var content = "";
for (var i = 0; i < games.length; i++) {
  var entry = template
    .replace(/POS/g, i + 1)
    .replace(/SLUG/g, games[i].slug)
    .replace(/NAME/g, games[i].name)
    .replace(/AUTHOR/g, games[i].author)
    .replace(/TWITTER/g, games[i].twitter)
    .replace(/WEBSITE/g, games[i].website)
    .replace(/GITHUB/g, games[i].github);
  entry = entry.replace("<a href='http:///'></a>", "-");
  content += entry;
}
document.getElementById("content").innerHTML = content;
```

次に、サービスワーカーを登録します。

```js
if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("/pwa-examples/js13kpwa/sw.js");
}
```

次のコードブロックは、ボタンがクリックされたときに通知の許可を要求します。

```js
var button = document.getElementById("notifications");
button.addEventListener("click", function (e) {
  Notification.requestPermission().then(function (result) {
    if (result === "granted") {
      randomNotification();
    }
  });
});
```

最後のブロックは、ゲームリストからランダムに選択されたアイテムを表示する通知を作成します。

```js
function randomNotification() {
  var randomItem = Math.floor(Math.random() \* games.length);
  var notifTitle = games[randomItem].name;
  var notifBody = "Created by " + games[randomItem].author + ".";
  var notifImg = "data/img/" + games[randomItem].slug + ".jpg";
  var options = {
    body: notifBody,
    icon: notifImg,
  };
  var notif = new Notification(notifTitle, options);
  setTimeout(randomNotification, 30000);
}
```

### サービスワーカー

すばやく見る最後のファイルはサービスワーカーです: `sw.js` — それは最初に `games.js` ファイルからデータをインポートします。

```js
self.importScripts("data/games.js");
```

次に、アプリシェルとコンテンツの両方から、キャッシュされるすべてのファイルのリストを作成します。

```js
var cacheName = "js13kPWA-v1";
var appShellFiles = [
  "/pwa-examples/js13kpwa/",
  "/pwa-examples/js13kpwa/index.html",
  "/pwa-examples/js13kpwa/app.js",
  "/pwa-examples/js13kpwa/style.css",
  "/pwa-examples/js13kpwa/fonts/graduate.eot",
  "/pwa-examples/js13kpwa/fonts/graduate.ttf",
  "/pwa-examples/js13kpwa/fonts/graduate.woff",
  "/pwa-examples/js13kpwa/favicon.ico",
  "/pwa-examples/js13kpwa/img/js13kgames.png",
  "/pwa-examples/js13kpwa/img/bg.png",
  "/pwa-examples/js13kpwa/icons/icon-32.png",
  "/pwa-examples/js13kpwa/icons/icon-64.png",
  "/pwa-examples/js13kpwa/icons/icon-96.png",
  "/pwa-examples/js13kpwa/icons/icon-128.png",
  "/pwa-examples/js13kpwa/icons/icon-168.png",
  "/pwa-examples/js13kpwa/icons/icon-192.png",
  "/pwa-examples/js13kpwa/icons/icon-256.png",
  "/pwa-examples/js13kpwa/icons/icon-512.png",
];
var gamesImages = [];
for (var i = 0; i < games.length; i++) {
  gamesImages.push("data/img/" + games[i].slug + ".jpg");
}
var contentToCache = appShellFiles.concat(gamesImages);
```

次のブロックはサービスワーカーをインストールし、上記のリストに含まれるすべてのファイルを実際にキャッシュします。

```js
self.addEventListener("install", function (e) {
  console.log("[Service Worker] Install");
  e.waitUntil(
    caches.open(cacheName).then(function (cache) {
      console.log("[Service Worker] Caching all: app shell and content");
      return cache.addAll(contentToCache);
    }),
  );
});
```

最後に、サービスワーカーは、キャッシュからコンテンツが利用できる場合はそれをキャッシュから取得し、オフライン機能を提供します。

```js
self.addEventListener("fetch", function (e) {
  e.respondWith(
    caches.match(e.request).then(function (r) {
      console.log("[Service Worker] Fetching resource: " + e.request.url);
      return (
        r ||
        fetch(e.request).then(function (response) {
          return caches.open(cacheName).then(function (cache) {
            console.log(
              "[Service Worker] Caching new resource: " + e.request.url,
            );
            cache.put(e.request, response.clone());
            return response;
          });
        })
      );
    }),
  );
});
```

### JavaScript データ

ゲームデータは、 JavaScript オブジェクト (`games.js`) の形式で `data` フォルダーにあります。

```js
var games = [
  {
    slug: "lost-in-cyberspace",
    name: "Lost in Cyberspace",
    author: "Zosia and Bartek",
    twitter: "bartaz",
    website: "",
    github: "github.com/bartaz/lost-in-cyberspace",
  },
  {
    slug: "vernissage",
    name: "Vernissage",
    author: "Platane",
    twitter: "platane\_",
    website: "github.com/Platane",
    github: "github.com/Platane/js13k-2017",
  },
  // ...
  {
    slug: "emma-3d",
    name: "Emma-3D",
    author: "Prateek Roushan",
    twitter: "",
    website: "",
    github: "github.com/coderprateek/Emma-3D",
  },
];
```

すべてのエントリは `data/img` フォルダーに独自の画像を持っています。 これは JavaScript でコンテンツセクションに読み込まれたコンテンツです。

次へ
--

次の記事では、サービスワーカーの助けを借りて、オフラインで使用するためにアプリシェルとコンテンツがどのようにキャッシュされるかについて詳しく説明します。

* 前のページ
* Overview: Progressive web apps
* 次のページ


通知とプッシュを利用して PWA を再エンゲージ可能にするには - プログレッシブウェブアプリ (PWA)

通知とプッシュを利用して PWA を再エンゲージ可能にするには
===============================

* 前のページ
* Overview: Progressive web apps
* 次のページ

アプリのコンテンツをキャッシュできるようにしてオフラインで動作させるのは、すばらしい機能です。 ユーザーがホーム画面にウェブアプリをインストールできるようにすることは、もっと良いことです。 しかし、ユーザーの操作のみに頼らず、プッシュメッセージと通知を使用すれば、さらに自動的に再エンゲージを行い新しいコンテンツが利用できるようになるたびに配信することができるようになります。

二つの API と一つの目標
--------------

Push API と Notifications API は 2 つの別々の API ですが、アプリで魅力的な機能を提供したい場合には、それらは一緒にうまく機能します。 プッシュは、クライアント側の介入なしにサーバーからアプリに新しいコンテンツを配信するために使用され、その操作はアプリのサービスワーカーによって処理されます。 サービスワーカーは、通知を使用して新しい情報をユーザーに表示するか、少なくとも何かが更新されたときにアラートすることができます。

それらはサービスワーカーと同じようにブラウザーウィンドウの外側で機能するため、アプリのページにフォーカスが合っていないときや閉じているときにも更新をプッシュして通知を表示できます。

通知
--

通知（notifications）から始めましょう — プッシュがなくても機能しますが、それらを組み合わせると非常に便利です。 はじめはそれらを個別に見てみましょう。

### パーミッションの要求

通知を表示するには、まずパーミッション（permission）を要求する必要があります。 ただちに通知を表示する代わりに、次のようにユーザーがボタンをクリックして要求したときにポップアップを表示することをお勧めします。

```js
var button = document.getElementById("notifications");
button.addEventListener("click", function (e) {
  Notification.requestPermission().then(function (result) {
    if (result === "granted") {
      randomNotification();
    }
  });
});
```

これは、次のようにオペレーティングシステム独自の通知サービスを使ったポップアップを表示します。

![Notification of js13kPWA.](/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Re-engageable_Notifications_Push/js13kpwa-notification.png)

ユーザーが通知を受け取ることを確認すると、アプリはそれらを表示できます。 ユーザー操作の結果は、デフォルト（`default`）、許可（`granted`）、または拒否（`denied`）になります。 ユーザーが後で選択する場合はデフォルトの選択肢が選択され、ユーザーがそれぞれ「はい」または「いいえ」をクリックすると他の 2 つが設定されます。

承認されると、パーミッションは通知とプッシュの両方に機能します。

### 通知の作成

サンプルアプリでは、利用可能なデータから通知を作成します — ゲームはランダムに選択され、選択されたものがコンテンツと共に通知を送ります — それは次のようにゲームの名前をタイトルとして設定し、本文で作者に言及し、そしてアイコンとして画像を表示します。

```js
function randomNotification() {
  var randomItem = Math.floor(Math.random() \* games.length);
  var notifTitle = games[randomItem].name;
  var notifBody = "Created by " + games[randomItem].author + ".";
  var notifImg = "data/img/" + games[randomItem].slug + ".jpg";
  var options = {
    body: notifBody,
    icon: notifImg,
  };
  var notif = new Notification(notifTitle, options);
  setTimeout(randomNotification, 30000);
}
```

迷惑すぎてユーザーによって無効にされるまで、新しいランダム通知が 30 秒ごとに作成されます — 実際のアプリの場合、通知はそれほど頻繁ではなく、より便利であるべきです。 Notifications API の利点は、オペレーティングシステムの通知機能を使用することです。 つまり、ウェブアプリを見ていなくてもユーザーに通知を表示でき、その通知はネイティブアプリで表示されるものと似ています。

プッシュ
----

プッシュは通知よりも複雑です — データをアプリに送り返すサーバーを購読（subscribe）する必要があります。 アプリのサービスワーカーはプッシュサーバーからデータを受け取ります。 このデータは通知システム、または必要に応じて別のメカニズムを使用して表示できます。

技術はまだ非常に初期段階にあります — いくつかの実用的な例は Google Cloud Messaging プラットフォームを使用しますが、VAPID（Voluntary Application Server Identification、自発的アプリケーションサーバー識別）をサポートするように書き直されています。 サービスワーカークックブックの例（英語）を調べたり、Firebase を使用してプッシュメッセージングサーバーをセットアップしたり、（例えば Node.js を使用して）独自のサーバーを構築したりすることができます。

前述のように、プッシュメッセージを受信できるようにするには、サービスワーカーが必要です。 その基本については、サービスワーカーで PWA をオフラインで動作させるの記事で既に説明しています。 サービスワーカーの内部には、プッシュサービス購読機構（push service subscription mechanism）が作成されています。

```js
registration.pushManager.getSubscription().then(/\* ... \*/);
```

ユーザーが購読すると、サーバーからプッシュ通知を受け取ることができます。

サーバー側からは、セキュリティ上の理由からプロセス全体を公開鍵と秘密鍵で暗号化する必要があります — アプリを使用してセキュリティ保護されていないプッシュメッセージをだれでも送信できるようにするのは恐ろしい考えです。 サーバーのセキュリティ保護の詳細については、ウェブプッシュデータ暗号化テストページ（英語）を参照してください。 サーバーは、ユーザーが購読したときに受信したすべての情報を保存するので、メッセージは後で必要なときに送信できます。

プッシュメッセージを受信するために、次のようにサービスワーカーファイルの `push` イベントを監視できます。

```js
self.addEventListener("push", function (e) {
  /\* ... \*/
});
```

データを取得してすぐにユーザーへの通知として表示できます。 これは、例えば、何かをユーザーに思い出させるために使用したり、アプリで利用可能な新しいコンテンツについてユーザーに知らせたりするために使用できます。

### プッシュの例

プッシュにはサーバー部分が機能する必要があるため、静的ファイルのみのホスティングを提供する GitHub Pages でホスティングされる js13kPWA の例に含めることはできません。 それはすべてサービスワーカークックブック（英語）で説明されています — Push Payload Demo を参照してください。

このデモは 3 つのファイルで構成されています。

* index.js — アプリのソースコードが含まれています。
* server.js — サーバー部分が含まれています（Node.js で書かれています）。
* service-worker.js — サービスワーカー固有のコードが含まれています。

これらすべてを探りましょう。

#### index.js

`index.js` ファイルは、次のようにサービスワーカーを登録することから始まります。

```js
navigator.serviceWorker
  .register("service-worker.js")
  .then(function (registration) {
    return registration.pushManager
      .getSubscription()
      .then(async function (subscription) {
        // registration part
      });
  })
  .then(function (subscription) {
    // subscription part
  });
```

js13kPWA デモで見たサービスワーカーよりも少し複雑です。 この特定のケースでは、登録後、登録オブジェクト（registration object）を使用して購読し、次に結果として得られた購読オブジェクト（subscription object）を使用してプロセス全体を完了します。

登録部分（registration part）では、コードは次のようになります。

```js
if (subscription) {
  return subscription;
}
```

ユーザーが既に購読している場合は、購読オブジェクトを返して購読部分（subscription part）に移ります。 そうでない場合は、次のように新しい購読を初期化します。

```js
const response = await fetch("./vapidPublicKey");
const vapidPublicKey = await response.text();
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
```

アプリはサーバーの公開鍵を取得してレスポンスをテキストに変換します。 それから Uint8Array に変換する必要があります（Chrome をサポートするため）。 VAPID キーの詳細については、VAPID で識別した WebPush 通知を Mozilla のプッシュサービス経由で送信する（英語）のブログ投稿を読むことができます。

アプリは `PushManager` を使用して新しいユーザーの購読をすることができます。 `PushManager.subscribe()` メソッドに渡される 2 つのオプションがあります — 1 つ目は `userVisibleOnly：true` で、これはユーザーに送信されたすべての通知が表示されることを意味します。 2 つ目は `applicationServerKey` で、これには、取得と変換に成功した VAPID キーが含まれます。

```js
return registration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: convertedVapidKey,
});
```

それでは購読部分（subscription part）に移りましょう — アプリは最初に Fetch を使って購読の詳細を JSON としてサーバーに送ります。

```js
fetch("./register", {
  method: "post",
  headers: {
    "Content-type": "application/json",
  },
  body: JSON.stringify({
    subscription: subscription,
  }),
});
```

次に、[Request sending a notification!（通知の送信依頼）] ボタンの `onclick` 関数を定義します。

```js
document.getElementById("doIt").onclick = function () {
  const payload = document.getElementById("notification-payload").value;
  const delay = document.getElementById("notification-delay").value;
  const ttl = document.getElementById("notification-ttl").value;

  fetch("./sendNotification", {
    method: "post",
    headers: {
      "Content-type": "application/json",
    },
    body: JSON.stringify({
      subscription: subscription,
      payload: payload,
      delay: delay,
      ttl: ttl,
    }),
  });
};
```

このボタンがクリックされると、`fetch` はサーバーに与えられたパラメータで通知を送るように要求します — `payload` は通知に表示されるテキストで、`delay` は通知が表示されるまでの遅延を秒単位で定義し、`ttl` は指定された期間サーバー上で通知を利用できるようにする存続時間（time-to-live）の設定で、これも秒単位で定義します。

それでは、次の JavaScript ファイルに進みましょう。

#### server.js

サーバー部分は Node.js で書かれており、適切な場所にホストする必要があります。 これは、まったく別の記事の主題です。 ここでは大まかな概要のみを説明します。

web-push モジュール（英語）は VAPID キーを設定するために使用され、それらがまだ利用できない場合は必要に応じて生成します。

```js
const webPush = require("web-push");

if (!process.env.VAPID\_PUBLIC\_KEY || !process.env.VAPID\_PRIVATE\_KEY) {
  console.log(
    "You must set the VAPID\_PUBLIC\_KEY and VAPID\_PRIVATE\_KEY " +
      "environment variables. You can use the following ones:",
  );
  console.log(webPush.generateVAPIDKeys());
  return;
}

webPush.setVapidDetails(
  "https://github.com/mdn/serviceworker-cookbook/",
  process.env.VAPID\_PUBLIC\_KEY,
  process.env.VAPID\_PRIVATE\_KEY,
);
```

次に、モジュールはアプリが処理する必要があるすべてのルートを定義してエクスポートします — VAPID 公開鍵の取得、登録、そして通知の送信です。 使用されている `index.js` ファイルの変数（`payload`、`delay`、および `ttl`）を見ることができます。

```js
module.exports = function (app, route) {
  app.get(route + "vapidPublicKey", function (req, res) {
    res.send(process.env.VAPID\_PUBLIC\_KEY);
  });

  app.post(route + "register", function (req, res) {
    res.sendStatus(201);
  });

  app.post(route + "sendNotification", function (req, res) {
    const subscription = req.body.subscription;
    const payload = req.body.payload;
    const options = {
      TTL: req.body.ttl,
    };

    setTimeout(function () {
      webPush
        .sendNotification(subscription, payload, options)
        .then(function () {
          res.sendStatus(201);
        })
        .catch(function (error) {
          console.log(error);
          res.sendStatus(500);
        });
    }, req.body.delay \* 1000);
  });
};
```

#### service-worker.js

最後に取り上げるファイルは、サービスワーカーです。

```js
self.addEventListener("push", function (event) {
  const payload = event.data ? event.data.text() : "no payload";
  event.waitUntil(
    self.registration.showNotification("ServiceWorker Cookbook", {
      body: payload,
    }),
  );
});
```

`push` イベントのリスナーを追加し、データから取得したテキストからなる `payload` 変数を作成し（またはデータが空の場合に使用する文字列を作成し）、通知がユーザーに表示されるまで待ちます。

それらがどのように処理されるかを知りたい場合は、サービスワーカークックブック（英語）の残りの例を調べてください — 完全なソースコードは GitHub で入手できます。 一般的な使い方だけでなく、ウェブプッシュ、キャッシュ戦略、パフォーマンス、オフラインでの作業など、多数の実用的な例があります。

* 前のページ
* Overview: Progressive web apps
* 次のページ


サービスワーカーで PWA をオフラインで動作させる - プログレッシブウェブアプリ (PWA)

サービスワーカーで PWA をオフラインで動作させる
==========================

* 前のページ
* Overview: Progressive web apps
* 次のページ

js13kPWA の構造と、基本シェルが起動し実行させる様子を見てきたので、サービスワーカーを使用したオフライン機能の実装方法を見てみましょう。 この記事では、 js13kPWA の例 (ソースコードはこちら) で使用されている実現方法を見てみましょう。 どのようにオフライン機能を追加するのかを学習します。

サービスワーカーの説明
-----------

サービスワーカー（Service Workers）は、ブラウザーとネットワーク間の仮想プロキシです。 これらはついにフロントエンド開発者が長年にわたって苦労してきた問題を修正します — 最も注目に値するのは、ウェブサイトのアセットを適切にキャッシュし、ユーザーのデバイスがオフラインのときにそれらを利用できるようにする方法です。

これらは、ページのメインの JavaScript コードとは別のスレッドで実行され、DOM 構造にアクセスすることはできません。 これは、従来のウェブプログラミングとは異なるアプローチを取り入れています — API はノンブロッキングで、異なるコンテキスト間で通信を送受信できます。 あなたはサービスワーカーに取り組むべき何かを与え、約束（Promise）ベースのアプローチを使用して準備ができているときはいつでも結果を受け取ることができます。

通知の処理、別のスレッドでの大量の計算など、オフライン機能を提供するだけではありません。 サービスワーカーは、ネットワーク要求を制御したり、それらを変更したり、キャッシュから取得したカスタム応答を提供したり、応答を完全に合成したりできるので、非常に強力です。

### セキュリティ

サービスワーカーは非常に強力であるため、安全なコンテキスト（HTTPS を意味する）でしか実行できません。 コードを本番環境に移行する前に最初に試してみたい場合は、いつでも localhost でテストするか GitHub Pages を設定することができます。 どちらも HTTPS をサポートしています。

オフライン優先
-------

「オフライン優先」または「キャッシュ優先」のパターンは、コンテンツをユーザーに提供するための最も一般的な戦略です。 リソースがキャッシュされてオフラインで利用可能な場合は、サーバーからダウンロードする前に最初にそれを返します。 まだキャッシュに入っていない場合は、ダウンロードして将来の使用に備えてキャッシュします。

PWA における「プログレッシブ」
-----------------

プログレッシブエンハンスメントとして適切に実装されている場合、サービスワーカーは、オフラインサポートを提供することで API をサポートする最新のブラウザーを使用しているユーザーにメリットをもたらすことができますが、従来のブラウザを使用しているユーザーにとっては何もだめになりません。

js13kPWA アプリのサービスワーカー
---------------------

十分な理論 — いくつかのソースコードを見てみましょう！

### サービスワーカーの登録

app.js ファイルで、新しいサービスワーカーを登録するコードを見ることから始めます。

**注** : ここでは es6 の**アロー関数**の構文をサービスワーカーの実装に使用しています。

```js
if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("./pwa-examples/js13kpwa/sw.js");
}
```

Service Worker API をブラウザーがサポートしている場合は、`ServiceWorkerContainer.register()` メソッドを使用してサイトに対して登録します。 その内容は `sw.js` ファイルにあり、登録が成功した後に実行できます。 これが `app.js` ファイルの中にある唯一のサービスワーカーのコードで、それ以外のサービスワーカー固有のものはすべて `sw.js` ファイル自体にあります。

### サービスワーカーのライフサイクル

登録が完了すると、`sw.js` ファイルが自動的にダウンロードされてからインストールされ、最後にアクティブになります。

#### インストール

API を使用すると、関心のある重要なイベントのイベントリスナーを追加できます — 最初のものは `install` イベントです。

```js
self.addEventListener("install", (e) => {
  console.log("[Service Worker] Install");
});
```

`install` リスナーで、キャッシュを初期化し、オフラインで使用するためにファイルをキャッシュに追加することができます。 js13kPWA アプリはまさにそれを行います。

まず、キャッシュ名を格納するための変数が作成され、アプリシェル（app shell）のファイルが 1 つの配列にリストされます。

```js
var cacheName = "js13kPWA-v1";
var appShellFiles = [
  "/pwa-examples/js13kpwa/",
  "/pwa-examples/js13kpwa/index.html",
  "/pwa-examples/js13kpwa/app.js",
  "/pwa-examples/js13kpwa/style.css",
  "/pwa-examples/js13kpwa/fonts/graduate.eot",
  "/pwa-examples/js13kpwa/fonts/graduate.ttf",
  "/pwa-examples/js13kpwa/fonts/graduate.woff",
  "/pwa-examples/js13kpwa/favicon.ico",
  "/pwa-examples/js13kpwa/img/js13kgames.png",
  "/pwa-examples/js13kpwa/img/bg.png",
  "/pwa-examples/js13kpwa/icons/icon-32.png",
  "/pwa-examples/js13kpwa/icons/icon-64.png",
  "/pwa-examples/js13kpwa/icons/icon-96.png",
  "/pwa-examples/js13kpwa/icons/icon-128.png",
  "/pwa-examples/js13kpwa/icons/icon-168.png",
  "/pwa-examples/js13kpwa/icons/icon-192.png",
  "/pwa-examples/js13kpwa/icons/icon-256.png",
  "/pwa-examples/js13kpwa/icons/icon-512.png",
];
```

次に、`data/games.js` ファイルからのコンテンツとともにロードされる画像へのリンクが 2 番目の配列に生成されます。 その後、両方の配列は `Array.prototype.concat()` 関数を使ってマージされます。

```js
var gamesImages = [];
for (var i = 0; i < games.length; i++) {
  gamesImages.push("data/img/" + games[i].slug + ".jpg");
}
var contentToCache = appShellFiles.concat(gamesImages);
```

それから、`install` イベント自体を管理できます。

```js
self.addEventListener("install", (e) => {
  console.log("[Service Worker] Install");
  e.waitUntil(
    caches.open(cacheName).then((cache) => {
      console.log("[Service Worker] Caching all: app shell and content");
      return cache.addAll(contentToCache);
    }),
  );
});
```

ここで説明が必要なことが 2 つあります — `ExtendableEvent.waitUntil` が行うことと、`caches` オブジェクトとは何か。

サービスワーカーは、`waitUntil` 内のコードが実行されるまでインストールされません。 それは約束（promise）を返します — インストールにはしばらく時間がかかるかもしれないので完了するまで待つこのアプローチが必要です。

`caches` は特定のサービスワーカーの範囲内でデータの保存を可能にする特別な `CacheStorage` オブジェクトです — ウェブストレージは同期的であるため、ウェブストレージへの保存は機能しません。 サービスワーカーでは、代わりに Cache API を使用します。

ここでは、指定した名前でキャッシュを開き、アプリが使用するすべてのファイルをキャッシュに追加するので、次回のロード時に利用可能になります（要求 URL で識別されます）。

#### アクティベーション

`activate` イベントもあり、これは `install` と同じ方法で使用されます。 このイベントは通常、不要になったファイルを削除し、一般的にアプリの後にクリーンアップするために使用されます。 私たちのアプリでそれをする必要はないので、それをスキップします。

### フェッチへの応答

また、自由に使える `fetch` イベントもあり、これは HTTP 要求がアプリから発するたびに発生します。 これは要求を傍受してカスタム応答でそれらに応答することを可能にするので非常に便利です。 これは簡単な使用例です。

```js
self.addEventListener("fetch", (e) => {
  console.log("[Service Worker] Fetched resource " + e.request.url);
});
```

応答は望むものなら何でも構いません — 要求されたファイル、そのキャッシュされたコピー、または特定のことを実行する JavaScript コードの一部 — 可能性は無限大です。

このサンプルアプリでは、リソースが実際にキャッシュ内にある限り、ネットワークではなくキャッシュからコンテンツを提供します。 アプリがオンラインかオフラインかに関係なく、これを行います。 ファイルがキャッシュにない場合、アプリはそれを提供する前にまずそこに追加します。

```js
self.addEventListener("fetch", (e) => {
  e.respondWith(
    caches.match(e.request).then((r) => {
      console.log("[Service Worker] Fetching resource: " + e.request.url);
      return (
        r ||
        fetch(e.request).then((response) => {
          return caches.open(cacheName).then((cache) => {
            console.log(
              "[Service Worker] Caching new resource: " + e.request.url,
            );
            cache.put(e.request, response.clone());
            return response;
          });
        })
      );
    }),
  );
});
```

ここでは、キャッシュ内のリソースを見つけ、存在する場合は応答を返そうとする関数を使用して、`fetch` イベントに応答します。 存在しない場合は、別のフェッチ要求を使用してネットワークからそれをフェッチし、次に応答がキャッシュに格納されるので、次に要求されたときに応答が使用可能になります。

`FetchEvent.respondWith` メソッドが制御を引き継ぎます — これは、アプリとネットワークの間のプロキシサーバーとして機能する部分です。 これにより、すべての要求に対して、必要な応答を返すことができます — サービスワーカーによって準備され、キャッシュから取得され、必要に応じて変更された。

それでおしまい！ 私たちのアプリはインストール時にそのリソースをキャッシュしてキャッシュからのフェッチでそれらを提供しているので、ユーザーがオフラインであっても機能します。 追加されるたびに新しいコンテンツもキャッシュします。

更新
--

まだカバーしておくべき 1 つのポイントがあります — 新しいアセットを含むアプリの新しいバージョンが利用可能になったときにどのようにサービスワーカーをアップグレードするのでしょうか？ これには、キャッシュ名のバージョン番号が重要です。

```js
var cacheName = "js13kPWA-v1";
```

これが v2 に更新されるとき、新しいキャッシュに（新しいファイルを含む）すべてのファイルを追加することができます。

```js
contentToCache.push("/pwa-examples/js13kpwa/icons/icon-32.png");

// ...

self.addEventListener("install", (e) => {
  e.waitUntil(
    caches.open("js13kPWA-v2").then((cache) => {
      return cache.addAll(contentToCache);
    }),
  );
});
```

新しいサービスワーカーがバックグラウンドでインストールされ、前のバージョン（v1）はそれを使用するページがなくなるまで正しく動作します — 新しいサービスワーカーがアクティブになり、古いページからページの管理を引き継ぎます。

キャッシュのクリア
---------

スキップした `activate` イベントを覚えていますか？ これは、不要になった古いキャッシュを消去するために使用できます。

```js
self.addEventListener("activate", (e) => {
  e.waitUntil(
    caches.keys().then((keyList) => {
      return Promise.all(
        keyList.map((key) => {
          if (key !== cacheName) {
            return caches.delete(key);
          }
        }),
      );
    }),
  );
});
```

これにより、必要なファイルだけがキャッシュに保存されるので、ゴミが残ることはありません — ブラウザーで利用可能なキャッシュスペースは限られているので、後で自分でクリーンアップすることをお勧めします。

その他のユースケース
----------

サービスワーカーが提供する機能は、キャッシュからファイルを提供することだけではありません。 大量の計算が必要な場合は、メインスレッドからそれらをオフロードしてワーカーで実行し、使用可能になったらすぐに結果を受け取ることができます。 パフォーマンス面では、今は必要ではないが近い将来にある可能性があるリソースをプリフェッチすることができるため、実際にそれらのリソースが必要な場合はアプリの速度が速くなります。

まとめ
---

この記事では、PWA をサービスワーカーとオフラインで連携させる方法について簡単に説明しました。 Service Worker API の背後にある概念と、それをより詳細に使用する方法についてもっと知りたい場合は、さらに詳しい資料をチェックしてください。

プッシュ通知を処理するときにもサービスワーカーを使用します — これについては後の記事で説明します。

* 前のページ
* Overview: Progressive web apps
* 次のページ