# 主题

> 用 CSS 自定义属性定制 React 颜色选择器的主题：修改颜色、尺寸和圆角，让面板适应容器，以及排查面板显示异常。

Source: https://chroma-panel.jscrate.dev/zh/react/handbook/theming
Last updated: 2026-09-21

React 颜色选择器的颜色、尺寸和圆角都来自 CSS 自定义属性。把它们设置在 `.cp-root` 上即可，没有设置的值保持默认。如果你用 Tailwind，也可以按部位传入 class，详见[使用 Tailwind 样式](https://chroma-panel.jscrate.dev/zh/react/handbook/tailwind)。

```css
.cp-root {
  --cp-accent: #e5484d;
  --cp-radius-lg: 4px;
  --cp-width: 280px;
}
```

没有设置的一律保持默认值。除非你传入 `theme`，否则面板会跟随系统配色方案，详见 [ChromaPanel 的 props](https://chroma-panel.jscrate.dev/zh/react/components/chroma-panel)。

## 完整变量

```css
.cp-root {
  --cp-surface: #ffffff;
  --cp-surface-raised: #f4f4f6;
  --cp-border: #d6d6da;
  --cp-text: #1c1c1e;
  --cp-text-muted: #6b6b70;
  --cp-accent: #2d7ff9;
  --cp-focus: #2d7ff9;
  --cp-radius-lg: 16px;
  --cp-radius: 10px;
  --cp-width: 320px;
  --cp-disc-size: 196px;
  --cp-panel-h: 344px;
  --cp-control-height: 32px;
}
```

其中有两个变量，修改之前最好先了解一下。

`--cp-control-height` 同时决定标签栏、文本输入框、取色器按钮和底部色块的尺寸，改一个值就能统一缩放所有控件。

`--cp-panel-h` 是为模式内容预留的高度。它在每个模式下都相同，所以切换标签页时面板不会改变大小。内容超出这个高度时会滚动。如果你希望每个模式按自身内容决定高度，就把它设为 `auto`，但要接受面板会跳动。

## 适应容器

面板默认宽度固定为 320px，并为模式内容预留固定的高度。这两者都是变量，所以可以让面板跟随你放置它的容器，首页上的那些卡片就是这么做的。

```tsx
import type { CSSProperties } from "react";

<ChromaPanel
  style={
    {
      "--cp-width": "100%",
      "--cp-panel-h": "auto",
    } as CSSProperties
  }
/>;
```

`CSSProperties` 没有索引签名，所以在 style 对象里写自定义属性时，必须先对对象做类型断言，否则 TypeScript 会报错。

`--cp-width: 100%` 让面板填满父元素，其他什么都不用改：色轮的尺寸是 `min(100%, var(--cp-disc-size))`，会跟着面板一起缩小，而不会溢出。

`--cp-panel-h` 是为模式内容预留的高度，这个变量值得弄清楚：

| 值             | 效果                                                                                 |
| -------------- | ------------------------------------------------------------------------------------ |
| 长度值（默认） | 每个模式都是这个高度，所以切换标签页时面板大小不变。内容较少的模式，下方会留出空白。 |
| `auto`         | 每个模式的高度由自身内容决定，不会留空白，但切换标签页时面板大小会变化。             |

只显示一个模式时，几乎总是应该用 `auto`：既然没有其他模式可切换，预留的高度只会留下一块空白。

> **限制较高模式的高度**
>
> 只有当面板本身有高度可供分配时，长度值才会限制内容高度。如果面板高度是自动的，内容会超出这个值继续撑高。给面板也设置一个
> `height`，模式内容就会在其中滚动，因为 `.cp-panel-host` 已经设置了
> `overflow-y: auto`。

```tsx
// Fills its container, and scrolls the palette rather than growing the page.
<ChromaPanel
  modes={["palettes"]}
  style={{ "--cp-width": "100%", height: 420 } as CSSProperties}
/>
```

## 面板显示不正常时

样式表位于 `@layer chroma-panel` 中，所以你的 CSS 总是优先生效。但这也意味着，那些并非针对选择器写的 CSS 同样会生效。你应用里任何未分层的元素选择器规则，都会压过这里的所有规则，不管这些规则的优先级有多高：

```css
/* This restyles the picker's swatches and tabs too. */
button {
  border-radius: 7px;
}
```

如果面板的尺寸或形状看起来不对，先找找有没有这样的规则。要么缩小它的作用范围，要么把你的重置样式放进一个层里：

```css
@layer reset, chroma-panel, utilities;
```

[使用 Tailwind 样式](https://chroma-panel.jscrate.dev/zh/react/handbook/tailwind#cascade-layers)中介绍了 Tailwind 项目里的同样排序方式。

## 自行加载 CSS

如果你有严格的 `style-src` 策略、需要提取关键 CSS，或者希望服务端渲染的标记在水合前就带有样式（见[服务端渲染](https://chroma-panel.jscrate.dev/zh/react/handbook/server-rendering)），请自己导入样式表：

```tsx
import "chroma-panel/styles.css";

<ColorInput injectStyles={false} />;
```

样式注入以 `getRootNode()` 为单位进行。选择器在 shadow root 或 iframe 中都能正常工作，而且即使有很多个面板，也只会生成一个 `<style>` 元素。

> **这不会减小打包体积**
>
> `injectStyles={false}` 只是让面板不再写入 `<style>` 标签。无论如何，CSS 都会由模块导入。它适用于 CSP 或关键 CSS 的场景。

## API 参考

### 样式函数

```ts
function injectStyles(css: string, id: string, node?: Node | null): void
```

Writes the stylesheet into the document, or into the shadow root the panel is inside. A no-op during server rendering, and when `injectStyles={false}`.

```ts
function setStyleNonce(provider: string | (() => string | undefined)): void
```

Sets the nonce put on the injected <style> element, for a strict style-src policy.

### CSS 变量

| Variable | Description |
| --- | --- |
| `--cp-accent` | Selection rings and the active tab. |
| `--cp-border` | Hairlines between parts. |
| `--cp-control-height` | Sizes the tab bar, the text inputs, the eyedropper and the footer swatch together, so one value scales every control at once. |
| `--cp-disc-size` | Diameter of the color wheel. |
| `--cp-focus` | The focus ring. |
| `--cp-panel-h` | Height reserved for the mode content. It is the same in every mode, which is what stops the panel resizing when you switch tabs. Set it to auto to let each mode size itself. |
| `--cp-radius` | Corner radius on controls inside the panel. |
| `--cp-radius-lg` | The panel's own corner radius. |
| `--cp-surface` | The panel background. |
| `--cp-surface-raised` | Inputs, the tab bar and other raised areas. |
| `--cp-text` | Primary text. |
| `--cp-text-muted` | Labels and secondary text. |
| `--cp-width` | Panel width. |
