# theme_color 与 background_color 清单成员

> theme_color 为已安装 PWA 的标题栏、状态栏与任务切换器着色；background_color 填充启动画面与首次绘制前的窗口。

`theme_color` 是操作系统与浏览器用于已安装应用外框的颜色：桌面端的标题栏、Android 的状态栏与任务切换器卡片，
以及安装对话框的强调色。`background_color` 是启动画面上应用图标背后、以及从启动到页面自身 CSS 完成绘制前
窗口内部的填充色。两者的存在是为了让点击图标与第一帧之间没有白屏闪一下。

Chrome 46、Edge 79、Samsung Internet 5.0、Android WebView 46 与 Android 上的 Firefox 79 读取这两个成员；
Safari 自 iOS 15 与 macOS 17 起读取 `theme_color`，但没有任何地方使用 `background_color`（BCD
`html.manifest.theme_color` 与 `html.manifest.background_color`）。桌面版 Firefox 不从清单安装应用，两者都不用。

## 成员

- **类型**：字符串，内容为 CSS `<color>`：颜色名称、十六进制、`rgb()`、`hsl()` 或引擎 CSS 解析器接受的
  任何其他形式。Chromium 把解析结果存为不透明颜色，alpha 通道会被丢弃。
- **默认值**：缺省。没有 `theme_color` 时引擎使用自己的外框颜色；没有 `background_color` 时启动画面为白色
  （Chromium）或系统背景色。
- **示例值**：`"theme_color": "#1a1a2e"`、`"background_color": "#1a1a2e"`。

CSS 解析器拒绝的值会被丢弃并提示 `property 'theme_color' ignored, 'bluish' is not a valid color.`
（同一消息也会写出 `background_color`），该成员随后按缺省处理（`manifest_parser.cc`）。

清单里的值只在页面显示之前算数。页面加载后，文档中的 `<meta name="theme-color">` 元素会覆盖该页的
`theme_color`；由于该元素接受 `media` 属性，页面可以为每种配色方案声明一个颜色，而清单做不到
（MDN，`<meta name="theme-color">`）。Chromium 只在启动画面与绘制前的窗口填充中读取 `background_color`，
因此页面的 `body` 背景必须设成同一个值，否则首次绘制时会出现一次肉眼可见的颜色跳变。

:::observed
Chrome 155（macOS 26，英文界面）的 DevTools > Application > Manifest 中，**Presentation** 一节：
**Theme color** 与 **Background color** 两行在解析后的值旁绘制一个色块；清单写 `"theme_color": "bluish"` 时，
**Errors and warnings** 下列出 `property 'theme_color' ignored, 'bluish' is not a valid color.`，
而 **Theme color** 一行留空。
:::

## 示例

示例共用一个深海军蓝品牌色 `#1a1a2e` 与一个浅色变体 `#f5f5fa`。

### 清单一种颜色，页面按浅色与深色各一种

清单携带的是页面尚不存在时使用的颜色，所以它放默认方案。两个 `<meta>` 元素在页面加载后接管，并随用户的
系统设置切换。

```json
{
  "theme_color": "#1a1a2e",
  "background_color": "#1a1a2e"
}
```

```html
<meta name="theme-color" content="#f5f5fa" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#1a1a2e" media="(prefers-color-scheme: dark)">
```

在 Android 上，页面一绘制状态栏就跟随匹配的 `<meta>`；启动画面期间无论配色方案如何都显示清单值。

### 交接时没有颜色跳变的启动画面

Chromium 用 `background_color`、最大的 `icons` 条目与 `name` 组成启动画面。在任何可能晚加载的样式表之前
把文档背景设为同一颜色，就能让启动画面到页面的交接不被察觉。

```css
:root {
  color-scheme: dark;
  background: #1a1a2e;
}
@media (prefers-color-scheme: light) {
  :root {
    background: #f5f5fa;
  }
}
```

浅色方案用户仍会看到海军蓝的启动画面，因为清单只有一个值；从海军蓝到 `#f5f5fa` 的跳变发生在首次绘制时，
持续一帧，这是不维护两份清单的代价。

### 让生效的主题色与页面保持一致

运行时没有任何接口报告系统外框采用了哪个颜色，所以页面读回自己当前生效的 `<meta>` 元素，把该值用于
页内的表面，例如吸顶页头。没有元素匹配时，代码回退到清单中写明的颜色。

```js
function activeThemeColor() {
  const dark = matchMedia('(prefers-color-scheme: dark)').matches;
  const metas = [...document.querySelectorAll('meta[name="theme-color"]')];
  const match = metas.find((m) => !m.media || matchMedia(m.media).matches === true);
  return match?.content ?? (dark ? '#1a1a2e' : '#f5f5fa');
}

document.querySelector('header').style.background = activeThemeColor();
matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
  document.querySelector('header').style.background = activeThemeColor();
});
```

监听器在桌面端很重要：用户可以在应用打开时切换系统配色方案，系统标题栏会自己更新，这段代码让页头跟上它。

## 另请参阅

- [icons 清单成员](/zh/reference/manifest/icons/)
- [name 与 short_name 清单成员](/zh/reference/manifest/name-short-name/)
- [iOS 与 Safari 上的 PWA](/zh/reference/platforms/ios-safari/)
- [Web Application Manifest: theme_color member](https://www.w3.org/TR/appmanifest/#theme_color-member)（w3.org）
- [Customize your app's theme and background colors](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/How_to/Customize_your_app_colors)（developer.mozilla.org）