# tabbed 显示模式与 tab_strip 清单成员

> display_override 中的 tabbed 值让已安装 PWA 拥有自己的标签栏，tab_strip 成员则配置固定的主标签页与新建标签按钮。

`tabbed` 是一种显示模式，让已安装应用在自己的窗口里拥有标签栏，用户可以并排打开多个作用域内的页面，
而没有浏览器地址栏。它只能通过 `display_override` 请求，不能写在 `display` 里；配套的 `tab_strip`
成员配置标签栏：一个带有自身 URL 作用域的固定主标签页，以及新建标签按钮打开的 URL。

Chrome 126、Edge 126 与 Samsung Internet 28.0 处理该值（BCD `html.manifest.display_override.tabbed`）；
Chrome for Developers 页面记录该特性已在 ChromeOS 发布，Windows、macOS 与 Linux 上的桌面版 Chrome
从同一里程碑起也为已安装应用显示标签栏。Firefox 157、Safari 27 与 Android WebView 跳过该条目，使用
`display_override` 中的下一个值或 `display`。

## 成员

- **类型**：`"tabbed"` 是 `display_override` 数组中的一个字符串。`tab_strip` 是对象，含两个可选键：
  `home_tab`（`false`，或一个带 `scope_patterns` 与 `icons` 的对象，`scope_patterns` 是相对清单 URL
  解析的 URL 模式对象数组）和 `new_tab_button`（带 `url` 的对象，相对清单 URL 解析，且必须在 `scope` 内）。
- **默认值**：没有 `tab_strip` 时，应用等同于
  `{ "tab_strip": { "new_tab_button": { "url": "<start_url>" } } }`，没有主标签页。只要最终生效的显示
  模式不是 `tabbed`，`tab_strip` 就被忽略。
- **示例值**：`"display_override": ["tabbed"]` 搭配
  `"tab_strip": { "home_tab": { "scope_patterns": [{ "pathname": "/dashboard/*" }] }, "new_tab_button": { "url": "/new" } }`。

主标签页是固定的：导航到匹配某条 `scope_patterns` 的 URL 会留在其中，导航到模式之外的 URL 则打开新的
应用标签页。存在 `home_tab` 但没有 `scope_patterns` 时，主标签页的作用域缩小到只有 `start_url`。
新建标签按钮只在其 `url` 落在主标签页作用域之外时才会绘制；落在作用域内则隐藏按钮，因为主标签页已经
覆盖了那个目的地（WICG 说明文档）。

:::observed
Chrome 155（macOS 26，英文界面）中，含 `"display_override": ["tabbed"]` 的已安装应用：
`matchMedia('(display-mode: tabbed)').matches` 在应用窗口内返回 `true`，同一源在浏览器标签页中打开时返回
`false`；应用窗口绘制标签栏，并在 `new_tab_button.url` 将要打开的位置显示一个 **+** 按钮。同一份清单在
Chrome 125 中打开，该查询返回 `false`，应用以 `display` 指定的 `standalone` 模式启动。
:::

## 示例

三份清单描述同一个项目管理应用：仪表盘在 `/dashboard/`，各项目页面在 `/projects/<id>/`。

### 以 standalone 作回退启用 tabbed

`tabbed` 放在 `display_override` 首位；`display` 保持 `standalone`，Chrome 125、Firefox 与 Safari 就会以
普通应用窗口启动。要让标签栏工作不需要别的东西，因为默认的 `tab_strip` 在 `start_url` 打开新标签页。

```json
{
  "start_url": "/dashboard/",
  "scope": "/",
  "display": "standalone",
  "display_override": ["tabbed"]
}
```

用这份清单，每个指向项目页面的链接都在新的应用标签页中打开，仪表盘只是其中一个标签页，和其他标签页一样可以关闭。

### 把仪表盘固定为主标签页

加入 `home_tab` 后，仪表盘成为无法关闭的第一个固定标签页，并吸收所有 `/dashboard/` 下的导航。新建标签按钮
指向 `/projects/new`，它在主标签页的模式之外，因此按钮会显示。

```json
{
  "start_url": "/dashboard/",
  "scope": "/",
  "display": "standalone",
  "display_override": ["tabbed"],
  "tab_strip": {
    "home_tab": {
      "scope_patterns": [{ "pathname": "/dashboard/*" }],
      "icons": [{ "src": "/icons/home-96.png", "sizes": "96x96" }]
    },
    "new_tab_button": { "url": "/projects/new" }
  }
}
```

若把 `new_tab_button.url` 改为 `/dashboard/`，按钮会被隐藏，因为那个目的地已经是主标签页。

### 按浏览器选定的模式调整导航

tabbed 应用可以让系统标签栏取代页内标签栏，但只有在模式被授予时才行。检查在启动时执行一次，
变化时再执行，因为用户可以把窗口在不同模式之间切换。

```js
const tabbed = matchMedia('(display-mode: tabbed)');

function applyMode(active) {
  document.documentElement.dataset.nav = active ? 'os-tabs' : 'in-page';
}

applyMode(tabbed.matches);
tabbed.addEventListener('change', (event) => applyMode(event.matches));
```

`data-nav="in-page"` 时应用渲染自己的标签栏；`os-tabs` 时隐藏该栏，并用 `window.open(url)` 打开项目页面，
让每个页面成为一个应用标签页。

## 另请参阅

- [display_override 清单成员](/zh/reference/manifest/display-override/)
- [display 清单成员](/zh/reference/manifest/display/)
- [桌面端 PWA 安装：Chrome、Edge 及更多](/zh/reference/installation/desktop-install/)
- [Manifest Incubations: tabbed application mode explainer](https://wicg.github.io/manifest-incubations/tabbed-mode-explainer.html)（wicg.github.io）
- [Tabbed application mode for PWAs](https://developer.chrome.com/docs/capabilities/tabbed-application-mode)（developer.chrome.com）