Storybook不直接渲染纯CSS库,需封装壳组件并全局引入CSS文件;否则因无JS模块导出而报错或空白。关键步骤:一、创建React壳组件映射原始类名;二、在preview.js中正确import CSS(路径须准确);三、通过props控制样式变量而非直接操作className。
Storybook 本身不渲染 CSS 组件——它渲染的是 JavaScript/TSX 组件。如果你的“CSS 组件库”(比如 Milligram、MDB UI Kit、css.gg)没有封装成可导入的 JS 模块,直接写 Button.stories.js 是跑不起来的,会报 ReferenceError 或空白页。
得先让 CSS 类名能被 Storybook 环境识别并生效,再配交互逻辑。下面分三步说清怎么做、为什么这么干、以及最容易卡住的地方。
milligram.min.css)只提供类名,没导出函数或 React 组件。你不能直接 import { Button } from 'milligram' ——它根本没这个导出。必须手动封装一层“壳组件”,哪怕只是个空 div 加 class:
例如 Milligram 的按钮:
立即学习“前端免费学习笔记(深入)”;
export const MilligramButton = ({ label, variant = 'default', disabled = false }) => ( <button className={`button ${variant === 'outline' ? 'button-outline' : ''} ${disabled ? 'disabled' : ''}`} disabled={disabled} > {label} </button>);
关键点:
className 必须拼对原始库的 class 名(查官网或源码,比如 Milligram 是 button,不是 btn).stories.js 里直接写 HTML 字符串——Storybook 的 HTML 模式不支持 JSX,但你用 @storybook/react 就必须走 React 组件流mdb.rtl.min.css),记得在 .storybook/preview.js 中按需引入对应 CSSargTypes 控制面板只对组件 props 生效,不是对 class 字符串生效。所以不能写 className: { control: 'text' } 然后指望它自动加到 DOM 上——那只是个字符串,没绑定逻辑。正确做法是:把可变 class 映射为 prop,再在组件内做条件拼接。
比如 css.gg 的 Airplane 图标支持 size 和 color:
export const Airplane = ({ size = '24px', color = '#000' }) => ( <svg style={{ width: size, height: size, color }} viewBox="0 0 24 24"> <path d="M..." /> </svg>);
对应 story 中这样配:
argTypes: { size: { control: { type: 'text' } }, color: { control: { type: 'color' } }}
注意:
class 属性控制尺寸/颜色——CSS 图标库往往靠内联样式或 data 属性驱动,查 icons/tsx/Airplane.tsx 源码确认机制data-* 属性(如 data-size),就得在壳组件里透传,不能只靠 classcontrol: 'select' 适合有限枚举值(如 ['sm', 'md', 'lg']),但要确保这些值真正在 CSS 中有对应规则两个必查点:
.storybook/preview.js 中是否用了 import?比如:import 'milligram/dist/milligram.min.css' —— 这行必须存在,且路径准确(node_modules/milligram/... 或相对路径)@storybook/html 框架,import 语句无效,得改用 preview.js 的 parameters.docs.container 注入 <link> 标签,或在 main.js 的 webpackFinal 中手动注入 CSS!important 仅用于调试,上线前必须删掉.stories.mdx 更合适。示例(Button.stories.mdx):
import { Meta } from '@storybook/blocks';import { Button } from './MilligramButton';<p><Meta title="Components/Button" /></p><h2>原生用法</h2><p><code><button class="button">Click me</button></code></p><h2>React 封装用法</h2><p><Button label="Click me" />
注意:
<code> 标签必须小写,且不能嵌套 HTML 标签——否则 MDX 解析失败{`<button class="button">`}</button> 包裹,而不是直接写 HTML 标签@storybook/blocks 是 v7+ 推荐方式,旧版 @storybook/addon-docs 的 Canvas / ArgsTable 块仍可用,但配置更琐碎真正麻烦的从来不是写几个 story 文件,而是确认 CSS 类名与实际渲染结果的一致性——它不报错,但就是不生效。多开 DevTools 的 Elements 和 Console 面板,盯着 class 列表和 computed styles 看,比反复改 argTypes 有用得多。