Storybook 本身并不直接渲染 CSS 组件,它渲染的是 JavaScript 或 TSX 组件。如果你的“CSS 组件库”(如 Milligram、MDB UI Kit、css.gg)没有封装成可导入的 JS 模块,直接编写一个 `Button.stories.js` 是无法运行的,这会导致 `ReferenceError` 或空白页。
必须先让那些 CSS 类名在 Storybook 环境中被识别并生效,然后才能搭配交互逻辑。下面分三步说明:如何操作、为什么这样做、以及最容易卡住的地方。
## 如何将纯 CSS 类名转换为 Storybook 可用的组件?
纯 CSS 库(例如 `milligram.min.css`)只提供类名,没有导出任何函数或 React 组件。你不能直接使用 `import { Button } from 'milligram'`,因为该库根本没有此导出。
必须手动封装一层“壳组件”,即使只是一个空的 `div` 加上 class 名。例如,Milligram 的按钮:
```jsx
export const MilligramButton = ({ label, variant = 'default', disabled = false }) => (
);
```
关键点:
- `className` 必须准确拼写原始库的类名,查看官方文档或源码,例如 Milligram 使用 `button`,而不是 `btn`。
- 不要在 `.stories.js` 中直接编写 HTML 字符串。Storybook 的 HTML 模式不支持 JSX,但使用 `@storybook/react` 时,必须使用 React 组件流程。
- 如果库支持 RTL(例如 `mdb.rtl.min.css`),请在 `.storybook/preview.js` 中按需引入对应的 CSS 文件。
## 如何让 class 变量可实时调整,而不是写死?
`argTypes` 控制面板仅对组件的 props 生效,而不是对 class 字符串直接生效。因此不能使用 `className: { control: 'text' }` 并期望它自动应用到 DOM 上,这只是一个字符串,没有绑定任何逻辑。
正确的做法是:将可变 class 映射为 prop,然后在组件内部进行条件拼接。
例如,css.gg 的 `Airplane` 图标支持 `size` 和 `color`:
```jsx
export const Airplane = ({ size = '24px', color = '#000' }) => (
);
```
相应的 story 配置如下:
```jsx
argTypes: {
size: { control: { type: 'text' } },
color: { control: { type: 'color' } }
}
```
注意几个常见的陷阱:
- 不要使用 `class` 属性控制尺寸或颜色,CSS 图标库通常依赖内联样式或 data 属性,需查看 `icons/tsx/Airplane.tsx` 源码确认机制。
- 如果库使用 `data-*` 属性(例如 `data-size`),则必须在壳组件中透传,不能仅依赖 class。
- `control: 'select'` 适用于有限枚举值(例如 `['sm', 'md', 'lg']`),但要确保这些值在 CSS 中有对应的规则。
## 为什么 Storybook 启动后 CSS 不生效?
最常见的原因是:CSS 文件未被 Storybook 加载,或者加载时机错误。
两个必查点:
- 检查 `.storybook/preview.js` 中是否使用了 `import`?例如 `import 'milligram/dist/milligram.min.css'`,该行必须存在,且路径正确(`node_modules/milligram/...` 或相对路径)。
- 如果使用 `@storybook/html` 框架,`import` 语句无效,需要在 `preview.js` 的 `parameters.docs.container` 中注入 `
` 标签,或在 `main.js` 的 `webpackFinal` 中手动注入 CSS。
- 打开浏览器 DevTools 的 Elements 面板,检查目标元素上是否具有预期的 class,以及是否被其他样式覆盖。当优先级冲突时,可以临时使用 `!important` 进行调试,但在上线前务必删除。
## 如何在 MDX 文档中直接展示原始 HTML 和 class 示例?
有些团队希望设计师能够复制粘贴原生 HTML,而不是 React 组件。此时,使用 `.stories.mdx` 更为合适。
示例(`Button.stories.mdx`):
```jsx
import { Meta } from '@storybook/blocks';
import { Button } from './MilligramButton';
## 原生用法
## React 封装用法
```
注意:
- `
` 标签必须小写,且不能嵌套 HTML 标签,否则 MDX 解析失败。
- 如果需要语法高亮,使用 `` {`