recursal/MDN huggingface dataset:
电池管理器
=====

指示设备电池当前是否正在充电的 Boolean 值

语法
--
```

var charging = battery.charging
```


返回当前是否正在对 `BatteryManager` 对象的设备充电，如果正在充电则返回 `true`，否则返回 `false`.

示例
--

### HTML


```html
<div id="charging">(charging state unknown)</div>
```

### JavaScript


```js
navigator.getBattery().then(function (battery) {
  var charging = battery.charging;

  document.querySelector("#charging").textContent = charging;
});
```

规范
--

| Specification |
| --- |
| Battery Status API # dom-batterymanager-charging |

浏览器兼容性
------

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

参见
--

* `BatteryManager`
* `Navigator.getBattery`
CustomEvent.initCustomEvent()
=============================

**已弃用:** 不再推荐使用该特性。虽然一些浏览器仍然支持它，但也许已从相关的 web 标准中移除，也许正准备移除或出于兼容性而保留。请尽量不要使用该特性，并更新现有的代码；参见本页面底部的兼容性表格以指导你作出决定。请注意，该特性随时可能无法正常工作。

**`CustomEvent.initCustomEvent()`** 方法初始化了一个 `CustomEvent` object. 如果该事件已经被分发出去，则不会在初始化过程中重复触发．

这类对象一定是由 `Document.createEvent()` 方法创建的。该方法被分发之前必须通过`EventTarget.dispatchEvent()`方法设置．一旦被分发则，则无法被重新设置．

**备注：** **该方法已经作废，不要在新项目中继续使用该方法。**

Instead use specific event constructors, like `CustomEvent()`. The page on Creating and triggering events (en-US) gives more information about the way to use these.

Syntax
------
```

event.initCustomEvent(type, canBubble, cancelable, detail);
```

### Parameters

`type`

类型`DOMString`，事件名称。

*`canBubble`*

类型`Boolean`，事件是否沿着 dom 树向上冒泡。

`cancelable`

类型`Boolean`，事件是否可取消。

*`detail`*

事件初始化时传入的数据。

Specifications
--------------

| Specification |
| --- |
| DOM Standard # dom-customevent-initcustomevent |

Browser compatibility
---------------------

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

See also
--------

* `CustomEvent`
* The constructor to use instead of this deprecated method: `CustomEvent()`.
CustomEvent：CustomEvent() 构造函数
==============================

**`CustomerEvent()`** 构造函数创建一个新的 `CustomEvent` 对象。

语法
--


```js
new CustomEvent(type)
new CustomEvent(type, options)
```

### 参数

`type`

提供事件名称的字符串。事件名称区分大小写。

`options` 可选

一个对象，*除 `Event()` 中定义的属性外*，该对象还可以具有以下属性：

`detail` 可选

与事件相关联的事件相关值。处理器可使用 `CustomEvent.detail` 属性获取该值。默认为 `null`。


### 返回值

一个新的 `CustomEvent` 对象。

示例
--


```js
// 创建自定义事件
const catFound = new CustomEvent("animalfound", {
  detail: {
    name: "猫",
  },
});
const dogFound = new CustomEvent("animalfound", {
  detail: {
    name: "狗",
  },
});

// 添加合适的事件监听器
obj.addEventListener("animalfound", (e) => console.log(e.detail.name));

// 触发事件
obj.dispatchEvent(catFound);
obj.dispatchEvent(dogFound);

// 控制台中输出“猫”和“狗”
```


额外的示例可以在创建和触发事件中找到。

规范
--

| Specification |
| --- |
| DOM Standard # ref-for-dom-customevent-customevent |

浏览器兼容性
------

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

参见
--

* `CustomEvent`
* 创建和触发事件
CustomEvent.detail
==================

接口 `CustomEvent` 的只读属性 **`detail`** （详情）返回在初始化事件对象时传递过来的任何类型数据。

**备注：** 此特性在 Web Worker 中可用

Syntax
------
```

 let myDetail = customEventInstance.detail;
```

### Return value

事件对象初始化时传递的任何类型数据。

Example
-------


```js
// add an appropriate event listener
obj.addEventListener("cat", function (e) {
  process(e.detail);
});

// create and dispatch the event
let event = new CustomEvent("cat", {
  detail: {
    hazcheeseburger: true,
  },
});
obj.dispatchEvent(event);

// Will return an object contaning the hazcheeseburger property
let myDetail = event.detail;
```

Specifications
--------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-customevent-detail② |

Browser compatibility
---------------------

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

See also
--------

* `CustomEvent`
Crypto.randomUUID()
===================

**安全上下文:** 此项功能仅在一些支持的浏览器的安全上下文（HTTPS）中可用。

`Crypto` 接口的 **`randomUUID()`** 方法用于通过密码学安全的随机数生成器生成第四版 UUID (en-US)。

语法
--


```js
randomUUID()
```

### 参数

无。

### 返回值

包含随机生成的、长度为 36 字符的第四版 UUID 字符串。

示例
--

通过全局的 `crypto` 属性访问该方法。


```js
/\* 假定 self.crypto.randomUUID() 可用 \*/

let uuid = self.crypto.randomUUID();
console.log(uuid); // 例如 "36b8f84d-df4e-4d49-b662-bcde71a8764f"
```

规范
--

| Specification |
| --- |
| Web Cryptography API # Crypto-method-randomUUID |

浏览器兼容性
------

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

参见
--

* `Web Crypto API`
* `crypto` 用于获取 `Crypto` 对象。
* `Crypto.getRandomValues`，用于获取任意个安全的随机字节的来源。
Crypto.getRandomValues()
========================

**`Crypto.getRandomValues()`** 方法让你可以获取符合密码学要求的安全的随机值。传入参数的数组被随机值填充（在加密意义上的随机）。

为了确保足够的性能，不使用真正的随机数生成器，但是它们正在使用具有足够熵值伪随机数生成器。它所使用的 PRNG 的实现与其他不同，但适用于加密的用途。该实现还需要使用具有足够熵的种子，如系统级熵源。

语法
--
```

cryptoObj.getRandomValues(typedArray);
```

### 参数

`typedArray`

是一个基于整数的 `TypedArray`，它可以是 `Int8Array`、`Uint8Array`、`Int16Array`、 `Uint16Array`、 `Int32Array` 或者 `Uint32Array`（**不可**使用 `Float32Array` 或者 `Float64Array`）。在数组中的所有的元素会被随机数重写。（注释：生成的随机数储存在 `typedArray` 数组上。）

### 异常事件

`QuotaExceededError` `DOMException`

如果请求的长度超过 65536 字节，则抛出该异常。

例子
--


```js
/\* 假设 window.crypto.getRandomValues 可用 \*/

var array = new Uint32Array(10);
window.crypto.getRandomValues(array);

console.log("Your lucky numbers:");
for (var i = 0; i < array.length; i++) {
  console.log(array[i]);
}
```

标准
--

| Specification |
| --- |
| Web Cryptography API # Crypto-method-getRandomValues |

浏览器兼容性
------

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

参见
--

* 通过 `Window.crypto` 获取 `Crypto` 对象。
* `Math.random`，一个非密码学安全的随机数来源。
Crypto.subtle
=============

**安全上下文:** 此项功能仅在一些支持的浏览器的安全上下文（HTTPS）中可用。

**`Crypto.subtle`** 只读属性返回一个 `SubtleCrypto` 对象，可以用来做低级加密运算。

值
-

一个可用于与 Web Crypto API 的低级加密功能交互的 `SubtleCrypto` 对象。

规范
--

| Specification |
| --- |
| Web Cryptography API # Crypto-attribute-subtle |

浏览器兼容性
------

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

参见
--

* `Crypto`
* `SubtleCrypto`
* 兼容性测试页面。
* 用于 IE11 和 Safari 的垫片。
WaveShaperNode.curve
====================

`WaveShaperNode` 接口的 `curve` 属性是一个描述要被应用的畸变的`Float32Array` (en-US) 数组。

数组的中间元素被应用于每个信号数值 `0`，第一个应用于信号数值 `-1`，最后一个应用于信号数值 `1`；小于 `-1` 或者大于 `1` 的数值分别按照 `-1` 和 `1` 来处理。

如有必要，使用线性插值计算畸变曲线的中间值。

**备注：** 数组的值可以是 `null` : 在这个情况下，不会有畸变被应用到输入的信号上。

语法
--


```js
var audioCtx = new AudioContext();
var distortion = audioCtx.createWaveShaper();
distortion.curve = myCurveDataArray; // myCurveDataArray is a Float32Array
```

### Value

一个 `Float32Array` (en-US).

示例
--

参见 `BaseAudioContext.createWaveShaper()` 以获取示例代码。

规范
--

| Specification |
| --- |
| Web Audio API # dom-waveshapernode-curve |

浏览器兼容性
------

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

参见
--

* 使用 Web Audio API (en-US)
WaveShaperNode.oversample
=========================

`WaveShaperNode` 接口的 `oversample` 属性是一个指示过采样是否必须使用的枚举值。过采样是一个用于在将畸变应用到音频信号之前创建更多的采样（上采样）的技术。

一旦被应用，采样的数值会被还原为初始的数值。这将通过避免一些混淆现象从而导致更好的结果，代价则是在畸变曲线上会有较低的精确度。

可用的`oversample` 值有：

| Value | Effect |
| --- | --- |
| `'none'` | 不使用过采样。 |
| `'2x'` | 在应用畸变曲线前将采样的数量翻倍。 |
| `'4x'` | 在应用畸变曲线前将采样的数量翻 4 倍。 |

语法
--


```js
distortion.oversample = enumeratedValue;
```

### 值

* 畸变是一个`WaveShaperNode`.
* 枚举值`'none'`， `'2x'`，或 `'4x'`。
示例
--

参见 `BaseAudioContext.createWaveShaper()` 以获取示例代码。

规范
--

| Specification |
| --- |
| Web Audio API # dom-waveshapernode-oversample |

浏览器兼容性
------

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

参见
--

* 使用 Web Audio API (en-US)
WaveShaperNode.WaveShaperNode()
===============================

Web Audio API 的 **`WaveShaperNode()`** 构造方法创建一个新的 `WaveShaperNode`对象，是一个可以用来表示非线性畸变的`AudioNode` 。

语法
--
```

var waveShaperNode = new WaveShaperNode(context, options)
```

### 参数

*继承* *`AudioNodeOptions` 字典的参数。*

*context*

`AudioContext`的一个引用。

*options* 可选

Options 参数如下：

* `curve`: 用于波形形成效果的修正曲线。输入信号通常在 [-1;1] 的范围间。
* `oversample`: 指定在应用修正曲线时会被使用的过采样的类别（如果有的话）。有效的值有'`none`', '`2x`', 或者'`4x`'。缺省情况下是'`none`'。

### 返回值

一个新的`WaveShaperNode`对象的实例。

规范
--

| Specification |
| --- |
| Web Audio API # dom-waveshapernode-waveshapernode |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.
Audio()
=======

**`Audio()`** 构造器创建并返回一个 `HTMLAudioElement`，可以将它附加到文档中以供用户交互，也可以用于管理和播放背景音乐。

语法
--
```

audioObj = new Audio(url);
```

### 参数

`url` 可选

一个可选的、包含音频文件 URL 的 `DOMString`。

### 返回值

新创建的 `HTMLAudioElement` 对象，被设置为播放指定 `url`的音频文件。新对象的 `preload` 属性被设置为 `auto` 且它的 `src` 属性被设置为具体的 URL 或 `null` （当没有提供 URL 时）。如果提供了 URL，浏览器在返回新对象之前开始异步加载媒体资源。

使用说明
----

你也可以使用其他元素创建方法，例如 `document` 对象的 `createElement()` 方法，去构建一个新的 `HTMLAudioElement`.

### 检测回放时机

提供三种方法给开发者，判断音频文件是否已经加载，允许开始回放：

* 检测 `readyState` 属性的值。如果值是 `HTMLMediaElement.HAVE_FUTURE_DATA`，说明有足够的数据开始回放并能至少播放一小段时间。如果值是 `HTMLMediaElement.HAVE_ENOUGH_DATA`，根据当前的下载速率，说明有足够的数据，你可以无干扰地播放至结束。
* 监听 `canplay` 事件。当足够的音频数据被发送至 `<audio>` 元素，能开始回放，即使可能出现中断时，会触发该事件。
* 监听 `canplaythrough` 事件。当音频应该没有干扰能够顺利播放时将会触发该事件。

基于事件的方法是最优的：


```js
myAudioElement.addEventListener("canplaythrough", (event) => {
  /\* 音频可以播放；如果权限允许则播放 \*/
  myAudioElement.play();
});
```

### 内存使用与管理

如果所有使用 `Audio()` 构造函数创建的 audio 元素被删除，根据 JavaScript 垃圾回收机制，如果播放正在进行，内存中的 audio 元素不会被移除。相反，音频将会继续播放并且它的对象会保留在内存中，直到播放结束或是被暂停（例如调用 `pause()`）。在那个时候，这个对象才会成为垃圾回收的目标。

规范
--

| Specification |
| --- |
| HTML Standard # dom-audio-dev |

浏览器兼容性
------

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

The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.

参见
--

* Web media technologies
* 实现了此接口的 HTML 元素：`<audio>`。
渐进式 Web 应用介绍
============

* Overview: js13kGames
* 下一页

这篇文章将会为你介绍渐进式 Web 应用（PWA），讨论一下它们到底是什么；相比于常规的 Web 应用，它又带来了哪些优势。

什么是渐进式 Web 应用？
--------------

PWA 指的是使用指定技术和标准模式来开发的 Web 应用，这同时赋予它们 Web 应用和原生应用的特性。

例如一方面，Web 应用更加易于发现：相比于安装应用，访问一个网站显然更加容易和迅速。你还可以通过链接来分享 Web 应用。

另一方面，原生应用与操作系统可以更加完美的整合，也因此为用户提供了无缝的用户体验。你可以通过安装应用使得它在离线的状态下也可以运行；相较于使用浏览器访问，用户也更喜欢通过点击主页上的图标来访问它们喜爱的应用。

PWA 赋予了我们创建同时拥有以上两种优势的应用的能力。

这并不是一个新概念；类似的想法已经在过去的 Web 平台上通过各种方法实现了多次。渐进式增强和响应式设计已经可以让我们构建对移动端友好的网站。在多年以前的 Firefox OS 的生态系统中，离线运行和安装 Web 应用就已经成为了可能。

除此之外，PWA 还提供了更多的特性，并且无需在 Web 已有的那些优秀特点上妥协。

什么使应用成为 PWA?
------------

正如前文所述，PWA 不是只使用一种技术创建的。它代表了构建 Web 应用程序的新理念，涉及一些特定的模式，API 和其他功能。一眼是看不出来一个 Web App 是不是 PWA 的。如果应用程序满足某些要求，或者实现了一组特定的功能，例如离线工作、可安装、易于同步、可以发送推送通知等，我们就可以将其视为 PWA。

此外，还有一些工具可以按百分比衡量应用的完整性。（Lighthouse目前是最受欢迎的工具）通过实施各种技术优势，我们可以使应用程序更加渐进式，从而最终获得更高的 Lighthouse 得分。但这只是一个粗略的指标。

辨别一个 Web 应用是否是 PWA 有一些关键原则。一个 PWA 应该具有以下特点：

* 可发现（Discoverable）, 可以通过搜索引擎发现。
* 可安装（Installable）, 可以出现在设备的主屏幕。
* 可链接（Linkable）, 可以简单地通过 URL 分享。
* 独立于网络（Network independent）, 可以在离线状态或者是在网速很差的情况下运行。
* 渐进式（Progressive）, 在老版本的浏览器仍旧可以使用，在新版本的浏览器上可以使用全部功能。
* 可重入（Re-engageable）, 无论何时有新的内容，都可以发送通知。
* 响应式（Responsive）, 在任何具有屏幕和浏览器的设备上可以正常使用——包括手机、平板电脑、笔记本、电视、冰箱等。
* 安全（Safe）, 在用户、应用和服务器之间的连接是安全的，第三方无法访问你的敏感数据。
### 这么做值得吗？

当然值得！只需要相对较小的代价就可以实现 PWA 的核心特性，而优势却是巨大的。例如：

* 减少应用安装后的加载时间，通过 Service Workers 来进行缓存，以此来节省带宽和时间。
* 当应用有可用的更新时，可以只更新发生改变的那部分内容。相比之下，对于一个原生应用而言，即便是最微小的改动也需要强制用户去再次下载整个应用。
* 外观和使用感受与原生平台更加融为一体——应用图标被放置在主屏幕上，应用可以全屏运行等。
* 凭借系统通知和推送消息与用户保持连接，对用户产生更多的吸引力，并且提高转换效率。

有许多知名的成功企业正在尝试 PWA 方案，选择增强的网站体验而不是原生应用。事实上它们也确实从中获得了显而易见的益处。PWA Stats 这个网站上分享了许多案例研究，可以证明以上提及的这些优势。

最著名的案例可能是印度最大的电子商务网站 Flipkart Lite，它在 2015 年重建为 PWA，转化率提高了 70%。AliExpress PWA 也得到了比 Web 应用或原生应用更好的效果，新用户的转换率提高了 104%。对比一下利润增长率和转换为 PWA 所需相对较少的工作量，PWA 的优势显而易见。

像 couponmoto 这样的早期新兴创业公司也开始使用 PWA 来推动更多的消费者参与，这表明 PWA 可以帮助小公司和大公司更有效地（重新）吸引用户。

你可以查看 pwa.rocks 上的列表以获取更多示例。特别值得一提的是 hnpwa.com，它列出了 Hacker News 网站的示例实现（而不是随处可见的 TodoMVC 应用程序），你可以在其中看到各种前端框架的使用。

你甚至可以使用 PWABuilder 网站在线生成 PWA。

对于 Service Worker 和消息推送，请务必查看 Service Worker 手册。这是一个在现代站点中使用 Service Worker 的方法集合。

PWA 非常值得一试，你可以自己查看它是否适用于你的应用程序。

浏览器支持
-----

如前所述，PWA 不依赖于单个 API，而是使用多种技术来实现提供最佳 Web 体验的目标。

PWA 所需的关键要素是 Service Worker 支持。值得庆幸的是，桌面和移动设备上的所有主流浏览器都支持 Service Worker。

至于其他功能，像是推送通知、通知功能和添加至主屏功能也得到了广泛的支持。目前，Safari 对 Web App Manifest 和添加至主屏的支持有限，并且不支持 Web 推送通知。但是，其他主流浏览器都支持这里的所有功能。

其中一些 API 是实验性的，文档仍在草稿中，但是 Flipkart 和 AliExpress 这样的成功案例应该也能说服你尝试在 Web 应用程序中实现一些 PWA 功能。

最重要的是，你应该遵循渐进增强理念：在客户端支持它们的情况下使用提供此类增强功能的技术，但如果客户端不支持，则仍然提供应用程序的基本功能。这样，应用对每个人都可用，但使用现代浏览器的人能更多地从 PWA 功能中受益。

一个示例应用程序
--------

在本系列文章中，我们将研究一个超级简单网站的源代码，该网站列出了 js13kGames 2017 竞赛中提交给 A-Frame category 的游戏的相关信息。你不必考虑网站上的实际内容，这里主要是学习如何在你自己的项目中使用 PWA 功能。

你可以在 mdn.github.io/pwa-examples/js13kpwa 找到在线版本（另请参阅源代码），我们将在接下来的几篇文章中对其进行详细解释。

现在，让我们转到本系列的第二部分，我们来看看这个示例应用程序的结构。

* Overview: js13kGames
* 下一页
渐进式 Web 应用的最佳实践
===============

渐进式 Web 应用（PWA）可以安装在设备上，并能像传统网站一样在 Web 浏览器中使用，因此 PWA 需要能够适应不同的环境和用户期望。

本文提供了一系列最佳实践，以帮助你确保你的 PWA 尽可能完善。

适配所有浏览器
-------

你的 PWA 基于 Web 技术。这意味着除了可以安装在设备上之外，PWA 也可以在 Web 浏览器中运行。为了确保兼容性，非常重要的是在各种浏览器和操作系统上测试你的应用。

考虑到用户可能使用的各种浏览器，满足广泛的潜在用户需求。使用特性检测可以让你为最广泛的受众提供可用的体验。

功能检测还有助于实现渐进增强，这是一种设计理念，可以让尽可能多的用户获得出色的体验。

通过渐进增强，你首先专注于使用最简单的技术使应用的核心功能可以在所有浏览器上运行，然后增强支持的设备上的体验。

例如，使用 HTML `<form>` 元素处理表单提交意味着该表单将在所有浏览器上工作，包括不支持 JavaScript 的浏览器。然后，你可以通过添加客户端验证和基于 JavaScript 的提交处理来逐步增强表单，以在兼容设备上获得更好的体验。

适配所有设备
------

类似于在各种浏览器上测试你的应用程序的重要性，跨设备测试也能确保你的应用能覆盖到更广泛的用户群体。

对于 PWA 来说，响应式设计对于确保任何屏幕大小的设备都能访问内容至关重要。用户都应能不受其设备屏幕大小的限制而访问所有的功能和内容。通过对不同视口大小重新排列内容，你可以优先显示重要的数据和操作。

确保用户可以通过任何访问你的内容的方式与你的应用程序进行交互。支持键盘和鼠标，以及触摸或触控笔输入方法。确保所有应用程序功能都可以通过任何输入方式访问。

最后，使用语义化的 HTML 元素而不是重新创建自己的按钮或表单元素，因为语义化的 HTML 元素可以直接支持所有用户输入方式。

提供离线体验
------

安装的应用程序的用户希望它们始终可用，即使在连接速度较慢或不可靠的网络或设备完全离线时也是如此。

### 自定义离线页面

至少，你的 PWA 应该提供一个自定义离线页面，告知用户他们处于离线状态，而不是显示通用的浏览器错误页面。自定义离线页面在不同的浏览器和设备上提供更一致的体验，并保持用户与你的应用程序的互动。

你可以通过使用 service worker 拦截网络请求，并在用户离线时响应并提供自定义离线页面。

### 离线操作

为了进一步提供类似应用程序的体验，你的 PWA 应该在用户离线时也能正常工作。这意味着用户可以在离线状态下继续使用你的应用程序的部分或全部功能。

考虑以下场景：用户撰写了一封长电子邮件并按下“发送”按钮，却没有意识到他们失去了网络连接。由于你的应用程序支持离线工作，该电子邮件将在本地保存，并在设备恢复在线状态时自动发送。

了解更多关于离线和后台操作的信息。

### 支持深链接

深链接是指指向应用程序域内特定页面的超链接。例如，你的应用程序的主页可以在 `https://example.com/` 上访问，但你也可以链接到特定产品页面，如 `https://example.com/products/123`。

能够通过唯一的 URL 引用任何资源是 Web 的最强大的特性之一。由于它们构建在 Web 技术上，PWA 可以并且应该利用这个特性。

通过唯一的 URL 使应用程序的不同部分可用，允许用户收藏夹、直接导航和在应用程序中共享特定内容。它还允许搜索引擎索引你的应用程序内容，并使其可以通过 web 搜索被发现。

### 提供快速的体验

用户对安装的应用程序和网站有不同的期望。用户预期网站在加载和导航上需要时间，特别是在网络连接较差的情况下。然而，他们期望安装的应用程序始终快速并能够提供响应。

应用程序加载和执行核心功能的速度在用户参与和留存方面起着关键作用。应用程序响应时间越长，用户放弃的可能性就越大。

有工具、API 和最佳实践可帮助衡量和提高性能。了解更多信息，请参阅 web 性能。

### 提供无障碍体验

无障碍对于确保每个人都可以使用你的应用程序至关重要，无论个人能力或其用于访问你的应用程序的设备如何。无障碍确保尽可能多的人可以使用你的应用程序。无障碍也是法律所要求的。此外，无障碍通常会为所有人（而不仅仅是那些有永久或临时残疾的人）带来更好的用户体验。

参见无障碍文档，以了解如何使你的应用程序提供无障碍体验。

### 提供类似应用的体验

#### 与操作系统集成

用户期望安装的 PWA 与任何安装的特定平台应用程序一样运行。为了提供用户期望的类似应用的体验，你可以以以下方式将你的应用程序与操作系统集成：

* 使用通知 API 向用户设备发送通知。
* 使用 `file_handlers` (en-US) Web 应用清单成员处理文件。
* 在应用图标上显示标记（badge） (en-US)。
* 启用应用程序之间的数据共享 (en-US)。

许多 Web 应用程序清单成员可用于自定义应用程序在用户设备上的显示方式，并在操作系统中更深入地集成。

#### 应用的外观和感觉

用户安装应用程序是为了获得比网站更专注的体验，并更高效地完成任务。他们期望应用程序更简洁，减少杂乱，并专注于最重要的任务。

通过考虑以下指南，确保你的 PWA 提供类似应用的体验：

* 使用独立显示模式 (en-US)为你的应用程序提供自己的独立窗口。
* 定义应用程序图标 (en-US)。
* 使用 `prefers-color-scheme` 媒体特性检测用户偏好的主题，并相应地调整应用的主题。
* 自定义应用的主题和背景颜色 (en-US)，以提供更精细的体验，使其更像一个特定于平台的应用程序。
* 简化内容，专注于应用程序允许用户完成的最重要的任务。这可能意味着删除传统网站上常见的大标题和页脚，而改用菜单隐喻来代替。
* 使用 `system-ui` `font-family`，使你的内容感觉更像是原生于平台，并且在无需用户下载自定义字体的情况下加载速度更快。
参见
--

* 如何创建一个良好的渐进式 Web 应用，来自 web.dev（2022）。
* 渐进式 Web 应用的最佳实践，来自 learn.microsoft.com（2023）。