# 安装式 PWA 中的 Fullscreen API

> 介绍安装式 PWA 如何进入和退出元素全屏、检测状态变化、处理请求拒绝，并提供应用内退出控件。

Fullscreen API 允许安装式 PWA 请求用可用屏幕区域显示某个元素，之后再退出该模式。它与 Web 应用清单的显示模式相互独立：`requestFullscreen()` 在启动后改变当前文档，清单则控制安装式应用如何打开。

## 支持情况

BCD `api.Element.requestFullscreen` 记录 Chrome、Edge、Firefox 和 Safari 的实现，并标出了部分选项与旧版本的限制。应根据返回的 Promise 和 `fullscreenchange` 事件判断结果，而不是根据应用已安装来推断成功（[Element.requestFullscreen()](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen)，MDN）。

## 语法

```js
await element.requestFullscreen()
await element.requestFullscreen(options)
await document.exitFullscreen()
```

`requestFullscreen()` 请求让元素进入全屏；`exitFullscreen()` 请求让文档恢复此前的呈现方式。

## 参数

可选对象可包含 `navigationUI`，取值为 `"auto"`、`"hide"` 和 `"show"`；MDN 还记载了用于选择 `ScreenDetailed` 目标的实验性 `screen` 选项。

转换完成后，请求 Promise 以 `undefined` 兑现。在 `fullscreenchange` 监听器中读取 `document.fullscreenElement`，即可区分进入与退出。

## 异常

MDN 记载了会以 `TypeError` 拒绝的情况：文档不是 fully active、元素已脱离文档、Permissions Policy 或访问控制不允许全屏、元素本身就是文档，或元素是已显示的 popover。请求通常还需要瞬时用户激活。

iframe 必须获准使用全屏。对于跨源内容，应按 MDN 的说明配置 `fullscreen` Permissions Policy 和 iframe 的 `allow` 属性。

:::caution
Web Platform Tests 源码把无用户激活用例命名为 `Element#requestFullscreen() rejects without user activation by default`，并断言 JavaScript `TypeError`。这个确切断言可在 WPT runner 中复现，不依赖特定厂商的控制台文本。
:::

## 示例

以下示例把进入、退出和呈现变化都留在页面内，因此即使浏览器拒绝请求，界面仍能继续使用。

### 检测支持情况

显示全屏控件前，先检测进入和退出全屏所需的两个方法。如果有任一方法不存在，就隐藏控件，让内容继续在页面内显示。

```js
const button = document.querySelector('#fullscreen');
const status = document.querySelector('#status');

if ('requestFullscreen' in Element.prototype && 'exitFullscreen' in Document.prototype) {
  button.hidden = false;
} else {
  button.hidden = true;
  status.textContent = '全屏不可用；内容保持内联显示。';
}
```

BCD 分别以 `api.Element.requestFullscreen` 和 `api.Document.exitFullscreen` 记录这两个方法（[Element.requestFullscreen()](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen)，MDN；[Document.exitFullscreen()](https://developer.mozilla.org/en-US/docs/Web/API/Document/exitFullscreen)，MDN）。

### 通过明确控件切换舞台

按钮点击提供用户激活。无支持时的分支让内容保持内联，`catch` 分支报告请求被拒绝，而不会假称已经进入全屏。

```html
<main id="stage" tabindex="-1">
  <button id="fullscreen" type="button">进入全屏</button>
  <p>演示内容</p>
  <p id="status" role="status"></p>
</main>

<script type="module">
  const button = document.querySelector('#fullscreen');
  const stage = document.querySelector('#stage');
  const status = document.querySelector('#status');

  if (!stage.requestFullscreen || !document.exitFullscreen) {
    button.hidden = true;
    status.textContent = '全屏不可用；内容保持内联显示。';
  } else {
    button.addEventListener('click', async () => {
      try {
        if (document.fullscreenElement) {
          await document.exitFullscreen();
        } else {
          await stage.requestFullscreen();
        }
      } catch (error) {
        status.textContent = `未进入全屏：${error.name}`;
      }
    });

    document.addEventListener('fullscreenchange', () => {
      const active = Boolean(document.fullscreenElement);
      button.textContent = active ? '退出全屏' : '进入全屏';
      status.textContent = active ? '全屏已启用。' : '全屏已关闭。';
    });
  }
</script>
```

按钮位于全屏元素内部，进入全屏后仍会显示，可用来从页面内退出全屏。

### 在全屏时调整舞台样式

使用 `:fullscreen` 伪类只修改当前全屏元素，不影响平时的内联呈现。

```css
#stage:fullscreen {
  display: grid;
  place-content: center;
  padding: 2rem;
  background: Canvas;
  color: CanvasText;
}
```

退出全屏后，该选择器不再匹配，因此无需用 JavaScript 清理，舞台就会恢复页面中的常规样式。

## 另请参阅

- [Fullscreen API](https://fullscreen.spec.whatwg.org/)（WHATWG）
- [Element.requestFullscreen()](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen)（MDN）
- [清单显示模式](/zh/reference/manifest/display/)
- [桌面端 PWA](/zh/reference/platforms/desktop/)
- [独立模式 PWA 的无障碍设计](/zh/guides/accessibility/)