# 主题 · HeroUI

> 使用 CSS 变量和全局样式自定义 HeroUI 的设计系统

- 页面: https://jiguang132.com/zh/systems/heroui/docs/getting-started/theming
- 改编自: HeroUI 文档 (Apache-2.0) @ 60edd8ed751b1d2a270623fbb182bbcfa8baa9af

HeroUI 使用 CSS 变量和 [BEM](https://getbem.com/) 类来实现主题化。你可以使用标准 CSS 自定义从颜色到组件样式的所有内容。


> 
  **想要创建你自己的主题？** 试试 [主题构建器](https://heroui.com/themes)，以可视化方式自定义颜色、圆角、字体等，然后导出 CSS 用于你的项目。


## 工作原理

HeroUI 的主题系统构建于 [Tailwind CSS v4](https://tailwindcss.com/docs/theme) 的主题之上。当你导入 `@heroui/styles` 时，它会使用 Tailwind 的内置调色板，将其映射到语义化变量，自动在浅色和深色主题之间切换，并使用 CSS 层和 `@theme` 指令进行组织。

**命名规则：**
- 不带后缀的颜色用作背景（例如 `--accent`）
- 带 `-foreground` 后缀的颜色用于该背景上的文本（例如 `--accent-foreground`）

## 快速开始

**应用主题：** 将主题类添加到 HTML 并将颜色应用到 body 上：

```html
<html class="light" data-theme="light">
  <body class="bg-background text-foreground">
    <!-- Your app -->
  </body>
</html>
```

**切换主题：**
```html
<!-- Light theme -->
<html class="light" data-theme="light">

<!-- Dark theme -->
<html class="dark" data-theme="dark">
```

**使用 [next-themes](https://github.com/pacocoursey/next-themes) 以编程方式切换主题（适用于 Next.js）：**

首先，用 `ThemeProvider` 包装你的应用：

```tsx
// app/providers.tsx
"use client";

import { ThemeProvider } from "next-themes";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="light">
      {children}
    </ThemeProvider>
  );
}
```

```tsx
// app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body className="bg-background text-foreground">
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
```

然后使用 `useTheme` 在主题之间切换：

```tsx
"use client";

import { useTheme } from "next-themes";

export function ThemeSwitch() {
  const { theme, setTheme } = useTheme();

  return (
    <button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
      Toggle {theme === "dark" ? "Light" : "Dark"} Mode
    </button>
  );
}
```

**覆盖颜色：**

```css
/* app/globals.css */
@import "tailwindcss";
@import "@heroui/styles";

:root {
  /* Override any color variable */
  --accent: oklch(0.7 0.25 260);
  --success: oklch(0.65 0.15 155);
}
```

> **注意**：完整的调色板和视觉参考请参见 [颜色](/systems/heroui/docs/getting-started/colors)。

> **深色模式**：如需基于 `next-themes` 与 HeroUI `useTheme` 钩子的完整配置指南，请参见 [深色模式](/systems/heroui/docs/getting-started/dark-mode)。

**创建你自己的主题：**


使用你的主题：

```css
/* app/globals.css */
@layer theme, base, components, utilities;

@import "tailwindcss";
@import "@heroui/styles";

@import "./src/themes/ocean.css" layer(theme); /* [!code highlight]*/
```

应用你的主题：

```html
<!-- index.html -->

<!-- Light ocean -->
<html data-theme="ocean">

<!-- Dark ocean -->
<html data-theme="ocean-dark">
```

## 自定义组件

**全局组件样式：** 使用 BEM 类覆盖任何组件：

```css
@layer components {
  /* Customize buttons */
  .button {
    @apply font-semibold tracking-wide;
  }

  .button--primary {
    @apply bg-blue-600 hover:bg-blue-700;
  }

  /* Customize accordions */
  .accordion__trigger {
    @apply text-lg font-bold;
  }
}
```

> **注意**：完整的样式参考请参见 [样式](/systems/heroui/docs/getting-started/styling)。

**查找组件类名：** 每个组件文档页面都会列出所有可用的类名（基类、修饰符、元素、状态）。示例：[Button 类名](/systems/heroui/docs/components/button#css-classes)

## 导入策略

**完整导入（推荐）：** 两行代码即可获得全部内容：

```css
@import "tailwindcss";
@import "@heroui/styles";
```

**按需导入：** 只导入你需要的内容：

```css
/* Define layers */
@layer theme, base, components, utilities;

/* Base requirements */
@import "tailwindcss";
@import "@heroui/styles/base" layer(base);
/* OR specific base file */
@import "@heroui/styles/base/base.css" layer(base);

/* Theme variables */
@import "@heroui/styles/themes/shared/theme.css" layer(theme);
@import "@heroui/styles/themes/default" layer(theme);
/* OR specific theme files */
@import "@heroui/styles/themes/default/index.css" layer(theme);
@import "@heroui/styles/themes/default/variables.css" layer(theme);

/* Components (all components) */
@import "@heroui/styles/components" layer(components);
/* OR specific component files */
@import "@heroui/styles/components/index.css" layer(components);
@import "@heroui/styles/components/button.css" layer(components);
@import "@heroui/styles/components/accordion.css" layer(components);

/* Utilities (optional) */
@import "@heroui/styles/utilities" layer(utilities);

/* Variants (optional) */
@import "@heroui/styles/variants" layer(utilities);
```

> **注意**：目录导入（例如 `@heroui/styles/components`）会自动解析为其对应的 `index.css` 文件。使用显式文件路径（例如 `@heroui/styles/components/button.css`）来导入单个组件的样式。

**Headless 模式：** 从头开始构建你自己的样式：

```css
@import "tailwindcss";
@import "@heroui/styles/base/base.css";

/* Your custom styles */
.button {
  /* Your button styles */
}
```

## 添加自定义颜色

将你自己的语义化颜色添加到主题中：

```css
/* Define in both light and dark themes */
:root,
[data-theme="light"] {
  --info: oklch(0.6 0.15 210);
  --info-foreground: oklch(0.98 0 0);
}

.dark,
[data-theme="dark"] {
  --info: oklch(0.7 0.12 210);
  --info-foreground: oklch(0.15 0 0);
}

/* Make the color available to Tailwind */
@theme inline {
  --color-info: var(--info);
  --color-info-foreground: var(--info-foreground);
}
```

现在你可以在组件中使用它：

```tsx
<div className="bg-info text-info-foreground">Info message</div>
```

## 变量参考

HeroUI 在 [`variables.css`](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/themes/default/variables.css) 中定义了三种类型的变量：

1. **基础变量（Base Variables）** — 不会变化的值，例如 `--white`、`--black`、间距以及排版
2. **主题变量（Theme Variables）** — 在浅色 / 深色主题之间切换的颜色，以及滚动条令牌（`--scrollbar-thumb`、`--scrollbar-width` 等）
3. **计算变量（Calculated Variables）** — 悬停状态、柔和（soft）变体以及边框 / 分隔线层级（每个浅色 / 深色主题中的 **Calculated Colors** 区块，使用 `color-mix()` 计算）

如需完整参考，请查阅：[颜色文档](/systems/heroui/docs/getting-started/colors)、[默认主题变量](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/themes/default/variables.css)、[共享主题工具](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/themes/shared/theme.css)

**Tailwind 主题桥接（`@theme inline`）：**

[`themes/shared/theme.css`](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/themes/shared/theme.css) 将语义化变量映射为 Tailwind 令牌（`--color-*`、`--radius-*`、`--ease-*`）。计算颜色引用的是 `variables.css` 中的底层变量（例如 `--surface-hover`、`--accent-soft`）—— 它们并不会在该文件中通过 `color-mix()` 内联展开：


表单控件依赖 `--field-*` 主题变量。悬停、聚焦及边框变体定义于 `variables.css` 的 **Calculated Colors** 区块中，并在 `theme.css` 中映射到 Tailwind 令牌（例如 `--color-field-hover: var(--field-hover)`）。在你的主题中覆盖 `--field-background`、`--field-hover` 及相关令牌，即可重新设计输入框、复选框、单选框和 OTP 输入槽的样式，而不会影响按钮或卡片等表面（surface）。

## 滚动条

HeroUI 为组件中的滚动区域（表格、弹出框、抽屉等）应用统一的滚动条样式。滚动条使用标准 CSS 属性（`scrollbar-width`、`scrollbar-color`、`scrollbar-gutter`），不再依赖 `::-webkit-scrollbar` 覆盖。

**模式** — 在 `<html>`、组件根元素或滚动插槽上设置 `data-scrollbar`：

| 模式 | `data-scrollbar` | 行为 |
|------|------------------|------|
| HeroUI 纤细 | *（未设置）* 或 `thin` | 使用主题令牌呈现的纤细滑块 |
| 操作系统 / 浏览器 | `default` | 原生滚动条（`auto`） |
| 隐藏 | `none` | 不显示滚动条（`scrollbar-width: none`） |

```html
<!-- 全局使用原生滚动条 -->
<html data-scrollbar="default">

<!-- 在某个子树中恢复 HeroUI 滚动条 -->
<main data-scrollbar="thin">
  ...
</main>

<!-- 在某个子树中隐藏滚动条（例如弹出框） -->
<div data-scrollbar="none">
  ...
</div>
```

**主题变量** — 在 [`variables.css`](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/themes/default/variables.css) 的浅色与深色主题区块中定义：

| 变量 | 描述 |
|------|------|
| `--scrollbar-thumb` | 滑块颜色（默认通过 `color-mix` 混入 15% 的 `--foreground`） |
| `--scrollbar-track` | 轨道颜色（默认 `transparent`） |
| `--scrollbar-gutter` | 滚动条间隙（默认 `auto`） |
| `--scrollbar-width` | `scrollbar-width` 属性（默认 `thin`） |
| `--scrollbar-color` | `scrollbar-color` 属性（默认为滑块颜色 + 轨道颜色） |
| `--scrollbar` | `--scrollbar-thumb` 的旧版别名 |

**全局自定义：**

```css
/* app/globals.css */
:root {
  --scrollbar-thumb: color-mix(in oklch, var(--accent) 30%, transparent);
  --scrollbar-gutter: auto;
}
```

**按滚动插槽** — 在组件上传入 `data-scrollbar`，或在外层包裹元素上覆盖相关令牌：

```tsx
<Table data-scrollbar="default">
  ...
</Table>

<Drawer.Content data-scrollbar="thin" />

<Calendar.YearPickerGrid data-scrollbar="none" />
```

**自定义溢出区域** — 在自己的元素上使用 `@heroui/styles` 提供的 `scrollbar`、`scrollbar-thin`、`scrollbar-default` 或 `scrollbar-none` 工具类。基于类的覆盖方式详见 [样式](/systems/heroui/docs/getting-started/styling)。

> **注意**：部分组件默认隐藏滚动条（日期选择器弹出框、颜色选择器、次级标签页）。嵌套的滚动插槽（例如日期选择器内部的日历年份选择器）会保留 HeroUI 滚动条，因为 `scrollbar-none` 只作用于其所在的元素本身，不会影响使用 `@apply scrollbar` 的后代元素。

## 资源

- [颜色文档](/systems/heroui/docs/getting-started/colors)
- [样式指南](/systems/heroui/docs/getting-started/styling)
- [Tailwind CSS v4 主题](https://tailwindcss.com/docs/theme)
- [BEM 方法论](https://getbem.com/)
- [OKLCH 颜色工具](https://oklch.com)

---

JGuang 全部资源索引: https://jiguang132.com/llms.txt
