Docs
Storybook Docs

主题

Watch a video tutorial

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

¥Storybook is theme-able using a lightweight theming API.

全局主题

¥Global theming

可以全局主题化 Storybook。

¥It's possible to theme Storybook globally.

Storybook 包含两个开箱即用的主题:"light" 和 "dark"。除非你将首选配色方案设置为深色,否则 Storybook 将使用浅色主题作为默认主题。

¥Storybook includes two themes that look good out of the box: "light" and "dark". Unless you've set your preferred color scheme as dark, Storybook will use the light theme as default.

确保你已安装 @storybook/manager-api@storybook/theming 软件包。

¥Make sure you have installed @storybook/manager-api and @storybook/theming packages.

npm install --save-dev @storybook/manager-api @storybook/theming

作为示例,你可以通过修改 .storybook/manager.js 来告诉 Storybook 使用 "dark" 主题:

¥As an example, you can tell Storybook to use the "dark" theme by modifying .storybook/manager.js:

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

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

¥When setting a theme, set a complete theme object. The theme is replaced, not combined.

主题文档

¥Theming docs

Storybook 文档 使用与 Storybook UI 相同的主题系统,但主题独立于主 UI。

¥Storybook Docs uses the same theme system as Storybook’s UI but is themed independently from the main UI.

假设你为 .storybook/manager.js 中的主 UI 定义了一个 Storybook 主题:

¥Supposing you have a Storybook theme defined for the main UI in .storybook/manager.js:

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

以下是在 .storybook/preview.js 中为文档指定相同主题的方法:

¥Here's how you'd specify the same theme for docs in .storybook/preview.js:

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

如果你想了解如何创建主题,请继续阅读。

¥Continue to read if you want to learn how to create your theme.

创建主题快速入门

¥Create a theme quickstart

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

¥The easiest way to customize Storybook is to generate a new theme using the create() function from storybook/theming. This function includes shorthands for the most common theme variables. Here's how to use it:

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

¥Inside your .storybook directory, create a new file called YourTheme.js and add the following:

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

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

¥If you're using brandImage to add your custom logo, you can use any of the most common image formats.

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

¥Above, we're creating a new theme that will:

  • 使用 Storybook 的 light 主题作为基准。

    ¥Use Storybook's light theme as a baseline.

  • 将侧边栏中的 Storybook 徽标替换为我们自己的徽标(在 brandImage 变量中定义)。

    ¥Replace Storybook's logo in the sidebar with our own (defined in the brandImage variable).

  • 添加自定义品牌信息。

    ¥Add custom branding information.

  • 通过 target 属性将品牌链接设置为在同一窗口中打开(而不是在新窗口中打开)。

    ¥Set the brand link to open in the same window (as opposed to a new one), via the target attribute.

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

¥Finally, we'll need to import the theme into Storybook. Create a new file called manager.js in your .storybook directory and add the following:

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

现在你的自定义主题将取代 Storybook 的默认主题,你将在 UI 中看到一组类似的更改。

¥Now your custom theme will replace Storybook's default theme, and you'll see a similar set of changes in the UI.

Storybook starter theme

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

¥Let's take a look at a more complex example. Copy the code below and paste it in .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.js.org/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,
});

上面,我们正在使用以下更改更新主题:

¥Above, we're updating the theme with the following changes:

  • 自定义调色板(在 appcolor 变量中定义)。

    ¥A custom color palette (defined in the app and color variables).

  • 自定义字体(在 fonttext 变量中定义)。

    ¥Custom fonts (defined in the font and text variables).

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

¥With the new changes introduced, the custom theme should yield a similar result.

Storybook custom theme loaded

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

¥Many theme variables are optional, the base property is NOT.

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

¥The @storybook/theming package is built using TypeScript, which should help create a valid theme for TypeScript users. The types are part of the package itself.

CSS 应急方案

¥CSS escape hatches

Storybook 主题 API 在设计上很狭窄。如果你想对 CSS 进行细粒度控制,所有 UI 和 Docs 组件都标有类名以实现这一点。使用风险自负,因为这是高级功能。

¥The Storybook theme API is narrow by design. If you want to have fine-grained control over the CSS, all UI and Docs components are tagged with class names to make this possible. Use at your own risk as this is an advanced feature.

要设置这些元素的样式,请将样式标签插入:

¥To style these elements, insert style tags into:

  • 对于 Storybook 的 UI,请使用 .storybook/manager-head.html

    ¥For Storybook’s UI, use .storybook/manager-head.html

  • 对于 Storybook 文档,请使用 .storybook/preview-head.html

    ¥For Storybook Docs, use .storybook/preview-head.html

Caution

就像你可以调整 预览的 head 标签 一样,Storybook 允许你通过 .storybook/manager-head.html 在管理器端修改代码。它在添加针对 Storybook HTML 的主题样式时很有用,但它是有代价的,因为 Storybook 的内部 HTML 可能会在发布周期的任何时候发生变化。

¥The same way as you can adjust your preview’s head tag, Storybook allows you to modify the code on the manager's side, through .storybook/manager-head.html. It can be helpful when adding theme styles that target Storybook's HTML, but it comes with a cost as Storybook's inner HTML can change at any time through the release cycle.

MDX 组件覆盖

¥MDX component overrides

如果你使用 MDX 进行文档,则还有一个 "themability" 级别。MDX 允许你使用 components 参数完全覆盖 Markdown 中渲染的组件。这是我们在 Storybook 中不正式支持的高级用法,但如果你需要它,它是一个强大的构造。

¥If you're using MDX for docs, there's one more level of "themability". MDX allows you to completely override the rendered components from Markdown using a components parameter. It's an advanced usage that we don't officially support in Storybook, but it's a powerful construct if you need it.

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

¥Here's how you might insert a custom code renderer for code blocks on the page, in .storybook/preview.js:

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

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

¥You can even override a Storybook block component.

以下是插入自定义 <Canvas /> 块的方法:

¥Here's how you might insert a custom <Canvas /> block:

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

插件和主题创建

¥Addons and theme creation

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

¥Some addons require specific theme variables that a Storybook user must add. If you share your theme with the community, make sure to support the official API and other popular addons, so your users have a consistent experience.

例如,流行的 Actions 插件就使用 react-inspector,它有自己的主题。提供其他主题变量以使其样式化,如下所示:

¥For example, the popular Actions addon uses react-inspector, which has themes of its own. Supply additional theme variables to style it like so:

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

使用插件作者的主题

¥Using the theme for addon authors

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

¥Reuse the theme variables above for a native Storybook developer experience. The theming engine relies on emotion, a CSS-in-JS library.

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

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

¥Use the theme variables in object notation:

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

或者使用模板字面量:

¥Or with template literals:

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