---
title: "样式"
description: "使用 CSS 自定义 ThunderPhone 语音小组件的外观"
---

该小组件呈现为带有内置浅色和深色主题的毛玻璃风格栏。可通过三个层级进行自定义：用于常见选项的属性、用于主题设置的 CSS 自定义属性，以及用于完全控制的 CSS 类覆盖。

<Note>
  这些样式选项适用于由 `ThunderPhoneWidget` React 组件和 `ThunderPhone.mount()` CDN 方法渲染的预构建小组件。如果您需要完全自定义的 UI，请改用[无头 Hook](/zh/widget/headless-hook)。
</Note>

---

## 主题

`theme` 属性控制小组件的配色方案。它会将 `tp--light` 或 `tp--dark` 类应用到小组件根元素：

```tsx
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  theme="dark"
/>
```

| 主题 | 类 | 描述 |
|-------|-------|-------------|
| `'light'` | `tp--light` | 浅色背景搭配深色文本。默认值。 |
| `'dark'` | `tp--dark` | 深色背景搭配浅色文本。 |

两种主题均采用带有背景模糊和细微透明效果的毛玻璃风格栏设计。

---

## CSS 自定义属性

该组件公开了可覆盖的 CSS 自定义属性（变量），让您无需修改单个类即可更改颜色。这些属性由应用于 `.tp-widget` 根元素的主题类（`.tp--light` 或 `.tp--dark`）定义：

| 属性 | 默认值（浅色） | 默认值（深色） | 说明 |
|----------|-----------------|-----------------|-------------|
| `--tp-accent` | `#000` | `#fff` | 强调色：开始按钮、波形条、连接圆点、已连接状态文本。通过 `primaryColor` 属性以**内联**方式设置。 |
| `--tp-bg` | `rgba(255, 255, 255, 0.82)` | `rgba(15, 15, 15, 0.85)` | 控件条背景（半透明；由 `--tp-glass` 模糊处理）。 |
| `--tp-surface` | `rgba(0, 0, 0, 0.04)` | `rgba(255, 255, 255, 0.07)` | 静音按钮背景。 |
| `--tp-surface-hover` | `rgba(0, 0, 0, 0.07)` | `rgba(255, 255, 255, 0.12)` | 静音按钮悬停背景。 |
| `--tp-border` | `rgba(0, 0, 0, 0.08)` | `rgba(255, 255, 255, 0.1)` | 控件条和按钮边框。 |
| `--tp-border-hover` | `rgba(0, 0, 0, 0.14)` | `rgba(255, 255, 255, 0.18)` | 悬停时的边框颜色。 |
| `--tp-text` | `rgba(0, 0, 0, 0.88)` | `rgba(255, 255, 255, 0.95)` | 主文本（标题、智能体名称）。 |
| `--tp-text-2` | `rgba(0, 0, 0, 0.5)` | `rgba(255, 255, 255, 0.55)` | 次要文本（副标题、状态行、通话计时器）。 |
| `--tp-glass` | `blur(32px) saturate(180%)` | `blur(32px) saturate(180%)` | 在控件条上创建玻璃效果的 `backdrop-filter`。 |
| `--tp-shadow` | 三层阴影堆叠 | 三层阴影堆叠 | 控件条的 `box-shadow`（光环 + 近层 + 远层）。 |
| `--tp-shadow-hover` | 三层阴影堆叠 | 三层阴影堆叠 | 为悬停抬升效果声明；当前未被任何规则应用。 |
| `--tp-glow` | `inset 0 1px 0 0 rgba(255,255,255,0.5)` | `inset 0 1px 0 0 rgba(255,255,255,0.06)` | 叠加到控件条阴影上的内部顶部高光。 |
| `--tp-connected` | `#059669` | `#34d399` | 已连接状态指示器颜色（状态圆点）。 |
| `--tp-error` | `#dc2626` | `#fb7185` | 错误状态文本颜色。 |
| `--tp-end-bg` | `rgba(239, 68, 68, 0.08)` | `rgba(251, 113, 133, 0.12)` | 结束通话按钮背景。 |
| `--tp-end-color` | `#ef4444` | `#fb7185` | 结束通话按钮图标颜色。 |
| `--tp-end-border` | `rgba(239, 68, 68, 0.12)` | `rgba(251, 113, 133, 0.15)` | 结束通话按钮边框。 |
| `--tp-end-hover` | `rgba(239, 68, 68, 0.14)` | `rgba(251, 113, 133, 0.2)` | 结束通话按钮悬停背景。 |
| `--tp-idle-opacity` | `0.4` | `0.3` | 为闲置状态变暗效果声明；当前未被任何规则应用。 |

### 覆盖自定义属性

通过 `primaryColor` 属性设置强调色：

```tsx
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  primaryColor="#e11d48"
/>
```

<Warning>
  `--tp-accent` 会通过 `primaryColor` 属性设置为**内联样式**，因此在样式表中覆盖 `--tp-accent` 不会生效。请通过该属性更改强调色。其他所有自定义属性均可在 CSS 中覆盖。
</Warning>

使用 CSS 覆盖其他自定义属性。请使用双类选择器（`.tp-widget.tp--light` / `.tp-widget.tp--dark`），这样无论样式表顺序如何，您的规则都会优先于定义默认值的主题类：

```css
.tp-widget.tp--light {
  --tp-bg: rgba(0, 0, 0, 0.9);
  --tp-text: rgba(255, 255, 255, 0.95);
  --tp-text-2: rgba(255, 255, 255, 0.55);
  --tp-border: rgba(255, 255, 255, 0.15);
}
```

---

## CSS 类

所有小部件类均以 `tp-` 为前缀，以避免与您现有的样式冲突。

| 类 | 元素 | 说明 |
|-------|---------|-------------|
| `.tp-widget` | 根包装器 | 固定定位容器（`position: fixed`，角落由 `position` 属性设置，`z-index: 9999`）。承载主题类和基础字体设置；自身不含视觉外观。 |
| `.tp--light` / `.tp--dark` | 主题修饰符 | 与主题一起应用于 `.tp-widget`；定义所有 `--tp-*` 自定义属性。 |
| `.tp-bar` | 栏 | 玻璃拟态胶囊主体：背景、背景模糊、边框、`99px` 圆角半径和阴影。宽度为 `300px`。 |
| `.tp-meta` | 文本块 | 所有文本的容器——空闲时为标题和副标题，通话期间为智能体名称和状态。 |
| `.tp-name` | 主标签 | 空闲时显示 `title` 属性；通话期间显示已连接智能体的名称（若无则回退使用 `title`）。 |
| `.tp-sub` | 副标题 | 空闲时显示的“当前可用”文本行。 |
| `.tp-start` | 空闲通话按钮 | 圆形强调色启动按钮（42px）。使用 `--tp-accent` 作为背景。 |
| `.tp-dot` | 连接圆点 | 连接时显示在栏左侧的脉冲强调色圆点。 |
| `.tp-wave` / `.tp-wave--idle` | 波形 | 五条柱状波形。`--idle` 会添加缓慢的呼吸动画；通话期间柱状条会随音频响应。 |
| `.tp-button` | 通话中按钮 | 通话中控制按钮的基础样式（42px，12px 圆角）。 |
| `.tp-button-group` | 按钮行 | 通话期间包装静音和结束按钮。 |
| `.tp-button--start` | 连接按钮变体 | 通话开始时显示的强调色变体。 |
| `.tp-button--mute` | 静音切换 | 在通话期间将麦克风静音或取消静音。使用 `--tp-surface`。 |
| `.tp-button--end` | 结束通话按钮 | 挂断通话。使用 `--tp-end-*` 调色板。 |
| `.tp-button--loading` | 加载修饰符 | 连接时降低按钮亮度。 |
| `.tp-icon` / `.tp-spin` | 图标 | 按钮图标尺寸；`tp-spin` 会为连接中的旋转指示器添加动画。 |
| `.tp-status` | 通话中状态块 | 在连接中、已连接或错误状态下包装状态行。 |
| `.tp-status__text` | 状态行 | 连接状态文本（例如“正在连接...”）或通话计时器。根据状态应用 `.tp-status--connected`（强调色）或 `.tp-status--error`（错误色）。 |
| `.tp-status__name` | 智能体名称槽位 | 状态块的一部分，但不会在当前栏布局中渲染——智能体名称会显示在 `.tp-name` 中。 |
| `.tp-status__dot` | 状态圆点 | 已连接状态的脉冲圆点样式（使用 `--tp-connected`）。 |

---

## 示例

### 通过 Props 自定义强调色

为小组件添加品牌风格的最简单方式：

```tsx
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  theme="light"
  primaryColor="#059669"
  title="Talk to support"
/>
```

### 通过 CSS 自定义颜色

覆盖自定义属性以完全控制颜色。请注意，强调色来自 `primaryColor` prop，而不是 CSS：

```tsx
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  primaryColor="#059669"
/>
```

```css
/* Emerald theme for everything else */
.tp-widget.tp--light {
  --tp-bg: rgba(236, 253, 245, 0.85);
  --tp-text: rgba(6, 78, 59, 0.95);
  --tp-text-2: rgba(4, 120, 87, 0.8);
  --tp-border: rgba(5, 150, 105, 0.2);
}
```

### 自定义尺寸

通过调整栏、按钮和文本尺寸，使小组件变大或变小：

```css
/* Wider bar */
.tp-bar {
  width: 340px;
}

/* Larger buttons (42px by default) */
.tp-start,
.tp-button {
  width: 56px;
  height: 56px;
}

/* Larger text */
.tp-name {
  font-size: 16px;
}

.tp-sub,
.tp-status__text {
  font-size: 14px;
}
```

### 隐藏文本标签

小组件的所有文本均位于 `.tp-meta` 中。完全隐藏它，仅保留波形和按钮：

```css
.tp-meta {
  display: none;
}
```

或者隐藏单独的部分：

```css
/* Hide only the idle "Available now" subtitle */
.tp-sub {
  display: none;
}

/* Hide only the in-call status line (connection state / timer) */
.tp-status {
  display: none;
}
```

<Note>
  空闲标签位于 `.tp-name`/`.tp-sub` 中，而非 `.tp-status`——仅隐藏 `.tp-status` 时，小组件空闲时仍会显示标题。
</Note>

### 特定主题覆盖

使用主题类定位特定主题：

```css
/* Only affect dark theme */
.tp--dark .tp-start {
  box-shadow: 0 0 20px rgba(255, 255, 255, 0.25);
}

/* Only affect light theme */
.tp-widget.tp--light {
  --tp-bg: rgba(255, 255, 255, 0.95);
}
```

---

## 使用 className 设定作用域

使用 React 组件时，传入 `className` prop，将覆盖规则限定到特定的小组件实例：

```tsx
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  theme="dark"
  className="support-widget"
/>
```

然后在 CSS 中定位该类：

```css
.support-widget.tp--dark {
  --tp-bg: rgba(30, 30, 46, 0.9);
}

.support-widget .tp-name {
  font-weight: 700;
}
```

这样您可以在同一页面上使用多个具有不同样式的小组件实例。通过各自的 `primaryColor` prop 为每个实例设置独立的强调色（CSS 无法覆盖 `--tp-accent`——它以内联方式设置）。

---

## 完全自定义 UI

如果 CSS 覆盖不足以满足需求，[无头 Hook](/zh/widget/headless-hook) 可让您完全掌控。您提供所有 HTML 和样式，而 `useThunderPhone` 负责处理语音会话。该 Hook 还提供 `audioLevelRef`，用于构建波形等音频响应式可视化效果。

```tsx
import { useThunderPhone } from '@thunderphone/widget'

function MyWidget() {
  const phone = useThunderPhone({
    publishableKey: 'pk_live_your_publishable_key',
  })

  return (
    <div className="my-totally-custom-widget">
      {/* Your own buttons, animations, layouts -- anything */}
      <button onClick={phone.state === 'connected' ? phone.disconnect : phone.connect}>
        {phone.state === 'connected' ? 'Hang up' : 'Call us'}
      </button>
      {phone.audio}
    </div>
  )
}
```

<Tip>
  当您需要音频响应式动画、自定义布局，或与现有组件库集成时，无头 Hook 是合适的选择。CSS 覆盖和自定义属性更适合快速调整主题。
</Tip>
