参加直播:周四,美国东部时间上午 11 点,Storybook 9 发布及 AMA(提问环节)
文档
Storybook 文档

主题设置

Storybook 可以使用轻量级主题设置 API 进行主题设置。

全局主题设置

可以全局设置 Storybook 的主题。

Storybook 内置了两种开箱即用的美观主题:“light” 和 “dark”。除非您将首选配色方案设置为深色,否则 Storybook 将默认使用浅色主题。

例如,您可以通过修改 .storybook/manager.js 文件,告诉 Storybook 使用 “dark” 主题。

.storybook/manager.js
import { addons } from 'storybook/manager-api';
import { themes } from 'storybook/theming';
 
addons.setConfig({
  theme: themes.dark,
});

设置主题时,请设置一个完整的主题对象。主题是替换,而不是合并。

文档主题设置

Storybook 文档 使用与 Storybook UI 相同的主题系统,但可以独立于主 UI 进行主题设置。

假设您已经在 .storybook/manager.js 文件中为主 UI 定义了 Storybook 主题。

.storybook/manager.js
import { addons } from 'storybook/manager-api';
import { themes } from 'storybook/theming';
 
addons.setConfig({
  theme: themes.dark,
});

以下是如何在 .storybook/preview.js 文件中为文档指定相同的主题。

.storybook/preview.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Preview } from '@storybook/your-framework';
 
import { themes } from 'storybook/theming';
 
const preview: Preview = {
  parameters: {
    docs: {
      theme: themes.dark,
    },
  },
};
 
export default preview;

如果您想了解如何创建自己的主题,请继续阅读。

创建主题快速入门

自定义 Storybook 最简单的方法是使用 storybook/theming 中的 create() 函数生成新主题。此函数包含最常用主题变量的缩写。以下是使用方法:

在您的 .storybook 目录中,创建一个名为 YourTheme.js 的新文件并添加以下内容:

.storybook/YourTheme.js
import { create } from 'storybook/theming';
 
export default create({
  base: 'light',
  brandTitle: 'My custom Storybook',
  brandUrl: 'https://example.com',
  brandImage: 'https://storybook.org.cn/images/placeholders/350x150.png',
  brandTarget: '_self',
});

如果您使用 brandImage 添加自定义 logo,可以使用任何最常见的图片格式。

上面,我们正在创建一个新主题,它将:

  • 使用 Storybook 的 light 主题作为基础。
  • 用我们自己的 logo(在 brandImage 变量中定义)替换 Storybook 侧边栏中的 logo。
  • 添加自定义品牌信息。
  • 通过 target 属性,设置品牌链接在当前窗口打开(而不是新窗口)。

最后,我们需要将主题导入到 Storybook 中。在您的 .storybook 目录中创建一个名为 manager.js 的新文件并添加以下内容:

.storybook/manager.js
import { addons } from 'storybook/manager-api';
import yourTheme from './YourTheme';
 
addons.setConfig({
  theme: yourTheme,
});

现在您的自定义主题将替换 Storybook 的默认主题,您将在 UI 中看到类似的变化。

Storybook starter theme

让我们看一个更复杂的示例。复制下面的代码并将其粘贴到 .storybook/YourTheme.js 文件中。

.storybook/YourTheme.js
import { create } from 'storybook/theming/create';
 
export default create({
  base: 'light',
  // Typography
  fontBase: '"Open Sans", sans-serif',
  fontCode: 'monospace',
 
  brandTitle: 'My custom Storybook',
  brandUrl: 'https://example.com',
  brandImage: 'https://storybook.org.cn/images/placeholders/350x150.png',
  brandTarget: '_self',
 
  //
  colorPrimary: '#3A10E5',
  colorSecondary: '#585C6D',
 
  // UI
  appBg: '#ffffff',
  appContentBg: '#ffffff',
  appPreviewBg: '#ffffff',
  appBorderColor: '#585C6D',
  appBorderRadius: 4,
 
  // Text colors
  textColor: '#10162F',
  textInverseColor: '#ffffff',
 
  // Toolbar default and active colors
  barTextColor: '#9E9E9E',
  barSelectedColor: '#585C6D',
  barHoverColor: '#585C6D',
  barBg: '#ffffff',
 
  // Form colors
  inputBg: '#ffffff',
  inputBorder: '#10162F',
  inputTextColor: '#10162F',
  inputBorderRadius: 2,
});

上面,我们通过以下更改更新了主题:

  • 自定义颜色调色板(在 appcolor 变量中定义)。
  • 自定义字体(在 fonttext 变量中定义)。

引入这些新更改后,自定义主题应该会产生类似的结果。

Storybook custom theme loaded

许多主题变量是可选的,但 base 属性不是

storybook/theming 模块是使用 TypeScript 构建的,这应该有助于为 TypeScript 用户创建有效的主题。类型本身就是包的一部分。

CSS 逃生通道

Storybook 主题 API 的设计初衷是保持简洁。如果您想对 CSS 进行精细控制,所有 UI 和 Docs 组件都带有类名,这使得控制成为可能。由于这是一项高级功能,请自行承担风险

要为这些元素添加样式,请将 style 标签插入到:

  • 对于 Storybook 的 UI,使用 .storybook/manager-head.html
  • 对于 Storybook 文档,使用 .storybook/preview-head.html
注意

与调整 preview 的 head 标签类似,Storybook 允许您通过 .storybook/manager-head.html 修改 manager 端代码。这对于添加针对 Storybook HTML 的主题样式可能很有帮助,但代价是 Storybook 的内部 HTML 在发布周期中随时可能发生变化。

MDX 组件覆盖

如果您将 MDX 用于文档,则还有一层“可主题化”的能力。MDX 允许您使用 components 参数完全覆盖从 Markdown 渲染的组件。这是一种我们不正式支持的高级用法,但如果需要,它是一个强大的构建块。

以下是如何在 .storybook/preview.js 文件中为页面上的 code 块插入自定义代码渲染器:

.storybook/preview.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Preview } from '@storybook/your-framework';
 
import { CodeBlock } from './CodeBlock';
 
const preview: Preview = {
  parameters: {
    docs: {
      components: {
        code: CodeBlock,
      },
    },
  },
};
 
export default preview;

您甚至可以覆盖 Storybook 块组件。

以下是如何插入自定义 <Canvas /> 块:

.storybook/preview.ts
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Preview } from '@storybook/your-framework';
 
import { MyCanvas } from './MyCanvas';
 
const preview: Preview = {
  parameters: {
    docs: {
      components: {
        Canvas: MyCanvas,
      },
    },
  },
};
 
export default preview;

插件与主题创建

某些插件需要 Storybook 用户必须添加的特定主题变量。如果您与社区共享您的主题,请确保支持官方 API 和其他热门插件,以便您的用户获得一致的体验。

例如,流行的 Actions 插件使用 react-inspector,它有自己的主题。可以通过提供额外的主题变量来设置其样式,如下所示:

addonActionsTheme: {
  ...chromeLight,
  BASE_FONT_FAMILY: typography.fonts.mono,
  BASE_BACKGROUND_COLOR: 'transparent',
}

面向插件作者使用主题

重用上述主题变量可以获得原生的 Storybook 开发体验。主题引擎依赖于 emotion,这是一个 CSS-in-JS 库。

YourTheme.js
import { styled } from 'storybook/theming';

在对象表示法中使用主题变量

MyComponent.js|jsx
const Component = styled.div(({ theme }) => ({
  background: theme.background.app,
  width: 0,
}));

或者使用模板字面量

MyComponent.js|jsx
const Component = styled.div`
  background: `${props => props.theme.background.app}`
  width: 0;
`;