Storybook Composition 中子项目样式冲突怎么解决?

❤伟伟 阅读 4

我在用 Storybook 的 Composition 功能把两个子项目的 stories 合并到主 Storybook 里,但发现子项目里的全局 CSS 影响了主项目的 UI 样式。明明两个项目用的都是 CSS Modules,但还是有样式污染,特别头疼。

我试过在子项目的 preview.js 里加了 addDecorator 包裹容器,也尝试限制作用域,但没效果。比如子项目里这段全局重置样式:

body {
  margin: 0;
  font-family: Arial, sans-serif;
}

button {
  background: #eee;
  border: 1px solid #ccc;
}

它直接把主 Storybook 里的按钮样式给覆盖了。有没有办法让每个子项目的样式只在自己的 stories 里生效,不影响其他项目?

我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
Prog.秋香
啊,这个坑我踩过。CSS Modules 防不住全局样式确实烦人,得用点狠招。试试这个方案:

1. 在子项目的 preview.js 里用 Shadow DOM 隔离样式:
import { addDecorator } from '@storybook/react';
import { useEffect } from 'react';

const ShadowDomDecorator = (Story) => {
useEffect(() => {
const shadowHost = document.createElement('div');
shadowHost.attachShadow({ mode: 'open' });
document.body.appendChild(shadowHost);
return () => shadowHost.remove();
}, []);

return (



);
};

addDecorator(ShadowDomDecorator);


2. 然后修改你的 webpack 配置,把全局样式打包进 shadow DOM:
// 在 storybook/main.js 里
webpackFinal: (config) => {
config.module.rules.push({
test: /.css$/,
use: [
{
loader: 'style-loader',
options: { injectType: 'shadowStyle' }
},
'css-loader'
]
});
return config;
}


3. 最后给你的全局样式加上 :host 限定(这个很多人会漏掉):
:host {
all: initial; /* 重置宿主样式 */
margin: 0;
font-family: Arial, sans-serif;
}

:host button {
background: #eee;
border: 1px solid #ccc;
}


这样处理后样式就被严格隔离了。虽然 Shadow DOM 方案有点重,但比用各种 hack 的 class 前缀靠谱多了。我项目里实测过,子项目随便怎么折腾都不会污染主项目。

唯一要注意的是某些 UI 库可能和 Shadow DOM 不太兼容,不过现代组件库基本都没问题。
点赞
2026-03-09 23:16