Storybook Backgrounds 背景配置完全指南:在 .storybook/preview 中自定义颜色选项与初始背景
导读
Backgrounds(背景色)是 Storybook 内置的核心功能,用于控制 Story 在 UI 中渲染时所处的背景颜色,帮助你在不同明暗背景下校验组件表现。本文将围绕当前仓库中 docs/_snippets/addon-backgrounds-options-in-preview.md 展开,讲解如何通过 .storybook/preview.* 中的 backgrounds.options 参数自定义可用的背景色列表,并通过 initialGlobals 设定初始背景色;同时结合 code/core/src/backgrounds 下的真实源码,剖析这些配置从参数解析到最终注入样式的底层链路。读完本文,你将能够配置全局背景色板、理解 options 键值与 globals 值之间的对应关系,并为任意组件或单个 Story 做局部覆写。
Backgrounds 功能与默认配置
Backgrounds 功能负责决定每个 Story 渲染时所处的画布背景。在 Storybook 中它是 Essentials 插件之一,相关完整文档见 docs/essentials/backgrounds.mdx。
开箱即用时,该功能内置了明暗两种背景。当前仓库中该功能的实现代码位于 code/core/src/backgrounds,其默认值定义在 code/core/src/backgrounds/defaults.ts:
export const DEFAULT_BACKGROUNDS: BackgroundMap = {
light: { name: 'light', value: '#F8F8F8' },
dark: { name: 'dark', value: '#333' },
};
也就是说,工具栏背景色下拉中默认展示两个选项:键 light(浅色 #F8F8F8)与键 dark(深色 #333)。文档示例片段中展示的 dark: '#333' 与源码默认值一致,light 的具体色值以你安装版本实际生效值为准。
你并不局限于这组默认色,可以通过 .storybook/preview.* 中的 parameters.backgrounds.options 完全自定义自己的色板,并用 initialGlobals 指定 Storybook 启动后 Story 默认采用的背景色。下面逐步展开。
在 .storybook/preview 中配置全局背景选项
配置入口
背景配置应放在 .storybook/preview.js|jsx|ts|tsx 的 parameters 中。由于 parameters 与 initialGlobals 遵循 Storybook 的层级合并规则,放在 preview.* 中的配置会对项目中所有组件与所有 Story 全局生效。
CSF 3 写法(JavaScript / 通用)
export default {
parameters: {
backgrounds: {
options: {
// 👇 Default options
dark: { name: 'Dark', value: '#333' },
light: { name: 'Light', value: '#F7F9F2' },
// 👇 Add your own
maroon: { name: 'Maroon', value: '#400' },
},
},
},
initialGlobals: {
// 👇 Set the initial background color
backgrounds: { value: 'light' },
},
};
CSF 3 写法(TypeScript / 通用)
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Preview } from '@storybook/your-framework';
const preview: Preview = {
parameters: {
backgrounds: {
options: {
// 👇 Default options
dark: { name: 'Dark', value: '#333' },
light: { name: 'Light', value: '#F7F9F2' },
// 👇 Add your own
maroon: { name: 'Maroon', value: '#400' },
},
},
},
initialGlobals: {
// 👇 Set the initial background color
backgrounds: { value: 'light' },
},
};
export default preview;
options 对象结构说明
backgrounds.options 的类型定义可以在 code/core/src/backgrounds/types.ts 中找到:
export interface Background {
name: string;
value: string;
}
export type BackgroundMap = Record<string, Background>;
- 对象键(如
dark、light、maroon):背景的标识符,用于在 toolbar 中定位、也用于globals.backgrounds.value的取值匹配。必须保持唯一且字符串形式; name:显示在工具栏下拉菜单中的文案(如Dark、Light、Maroon);value:实际应用在画布上的 CSS 颜色值,支持任意合法的 CSS 颜色表达(十六进制、rgb()、rgba()、命名颜色等)。
示例中先“重写”了默认的两个选项,再新增自定义色 maroon。这种写法意味着:preview 级别的 options 会覆盖整个默认色板。若你只需要在默认明暗基础上追加颜色,请在对象中同时保留 dark/light 键(如示例所示),否则它们会消失。
用 initialGlobals 设置初始背景
initialGlobals 负责设置 Storybook 启动时的初始全局状态。对 Backgrounds 而言,其全局状态以 backgrounds 为命名空间(见 code/core/src/backgrounds/preview.ts):
const initialGlobals: Record<string, GlobalState> = {
[PARAM_KEY]: { value: undefined, grid: false },
};
value 必须与 options 中的某个键匹配。例如上面的配置将 value 设为 'light',于是首屏 Story 会直接以浅色背景 #F7F9F2 渲染,无需手动切换。这一设计也支持仅通过 initialGlobals 换初始色、而不改动 options 色板的常见需求。
CSF Next 时代的写法(definePreview)
在 CSF Next 实验语法中,.storybook/preview 使用 definePreview() 包装配置,parameters 与 initialGlobals 的写法保持不变。以下展示当前仓库文档中给出的各渲染器变体。
React
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)
import { definePreview } from '@storybook/your-framework';
export default definePreview({
parameters: {
backgrounds: {
options: {
// 👇 Default options
dark: { name: 'Dark', value: '#333' },
light: { name: 'Light', value: '#F7F9F2' },
// 👇 Add your own
maroon: { name: 'Maroon', value: '#400' },
},
},
},
initialGlobals: {
// 👇 Set the initial background color
backgrounds: { value: 'light' },
},
});
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)
import { definePreview } from '@storybook/your-framework';
export default definePreview({
parameters: {
backgrounds: {
options: {
// 👇 Default options
dark: { name: 'Dark', value: '#333' },
light: { name: 'Light', value: '#F7F9F2' },
// 👇 Add your own
maroon: { name: 'Maroon', value: '#400' },
},
},
},
initialGlobals: {
// 👇 Set the initial background color
backgrounds: { value: 'light' },
},
});
Vue 3
import { definePreview } from '@storybook/vue3-vite';
export default definePreview({
parameters: {
backgrounds: {
options: {
// 👇 Default options
dark: { name: 'Dark', value: '#333' },
light: { name: 'Light', value: '#F7F9F2' },
// 👇 Add your own
maroon: { name: 'Maroon', value: '#400' },
},
},
},
initialGlobals: {
// 👇 Set the initial background color
backgrounds: { value: 'light' },
},
});
import { definePreview } from '@storybook/vue3-vite';
export default definePreview({
parameters: {
backgrounds: {
options: {
// 👇 Default options
dark: { name: 'Dark', value: '#333' },
light: { name: 'Light', value: '#F7F9F2' },
// 👇 Add your own
maroon: { name: 'Maroon', value: '#400' },
},
},
},
initialGlobals: {
// 👇 Set the initial background color
backgrounds: { value: 'light' },
},
});
Angular
import { definePreview } from '@storybook/angular';
export default definePreview({
parameters: {
backgrounds: {
options: {
// 👇 Default options
dark: { name: 'Dark', value: '#333' },
light: { name: 'Light', value: '#F7F9F2' },
// 👇 Add your own
maroon: { name: 'Maroon', value: '#400' },
},
},
},
initialGlobals: {
// 👇 Set the initial background color
backgrounds: { value: 'light' },
},
});
Web Components
import { definePreview } from '@storybook/web-components-vite';
export default definePreview({
parameters: {
backgrounds: {
options: {
// 👇 Default options
dark: { name: 'Dark', value: '#333' },
light: { name: 'Light', value: '#F7F9F2' },
// 👇 Add your own
maroon: { name: 'Maroon', value: '#400' },
},
},
},
initialGlobals: {
// 👇 Set the initial background color
backgrounds: { value: 'light' },
},
});
import { definePreview } from '@storybook/web-components-vite';
export default definePreview({
parameters: {
backgrounds: {
options: {
// 👇 Default options
dark: { name: 'Dark', value: '#333' },
light: { name: 'Light', value: '#F7F9F2' },
// 👇 Add your own
maroon: { name: 'Maroon', value: '#400' },
},
},
},
initialGlobals: {
// 👇 Set the initial background color
backgrounds: { value: 'light' },
},
});
注意:不同渲染器对应不同的包名,示例中的 @storybook/your-framework 需要替换为实际使用的包(如 @storybook/react-vite、@storybook/nextjs、@storybook/vue3-vite、@storybook/angular、@storybook/web-components-vite 等),具体以 code/addons 及各框架渲染器实际导出的 Preview 类型为准。
底层原理:从 options 到画布背景样式
在 .storybook/preview 里声明的这段配置,最终由 Backgrounds 的预览插件消费。其入口在 code/core/src/backgrounds/preview.ts,通过 definePreviewAddon 把装饰器 withBackgroundAndGrid、默认参数与初始全局状态注册进 Storybook。其中默认参数(code/core/src/backgrounds/preview.ts)为 disable: false,grid 默认 cellSize: 20、opacity: 0.5、cellAmount: 5。
真正把配置应用出去的是装饰器 code/core/src/backgrounds/decorator.ts,关键处理逻辑可以概括为:
- 读取配置:从
parameters[backgrounds]解构出options(缺省时回退为DEFAULT_BACKGROUNDS)、disable与grid; - 解析全局值:从
globals[backgrounds]取出value(兼容字符串或{ value }两种形态,见 types.ts),即当前选中的背景键; - 查表取值:用该键在
options中查找对应条目,取value字段作为 CSS 颜色;若找不到匹配,则退化为'transparent'; - 注入样式:通过
addBackgroundStyle向.sb-show-main(story 模式)或 docs 模式下的#anchor--… .docs-story容器注入background: <color> !important;样式(decorator.ts); - 禁用判断:
shownBackground = !!item && !disable,只有当选中项存在且未禁用该功能时,才会真的渲染背景色。
这解释了为什么 initialGlobals.backgrounds.value 必须是 options 的某个键——它本质上是查表的索引。同时也可以看到,当配置的 options 为空对象或未提供时,代码会自动使用默认的明暗两项作为兜底。
此外,装饰器会遵循系统 prefers-reduced-motion 设置,仅在允许动画时注入 transition: background-color 0.3s(decorator.ts),避免无障碍场景下不必要的色彩过渡。
局部覆写:组件级与 Story 级 options
除了在 preview.* 全局配置,backgrounds 参数遵循 Storybook 的参数继承机制,可在组件 Meta 层或单个 Story 层进行局部覆写。
例如,仅针对某个组件的全部 Story 调整色板,可在其 Button.stories.ts 中配置 parameters.backgrounds.options,完整的多渲染器示例见 docs/_snippets/addon-backgrounds-options-in-meta.md,核心思路如下:
const meta = {
component: Button,
parameters: {
backgrounds: {
options: {
// 👇 Override the default `dark` option
dark: { name: 'Dark', value: '#000' },
// 👇 Add a new option
gray: { name: 'Gray', value: '#CCC' },
},
},
},
} satisfies Meta<typeof Button>;
export default meta;
在该例子中,dark 选项在组件层级被改写为 #000,并新增 gray 选项。结合 Storybook 的合并规则,这会对该组件下的所有 Story 生效。
为指定 Story 固定背景(globals)
如果想让某个 Story 永远渲染在指定背景上(例如需要展示“深色模式下”的效果),可以通过 globals 直接绑定颜色,示例参见 docs/_snippets/addon-backgrounds-define-globals.md:
export default {
component: Button,
globals: {
// 👇 Set background value for all component stories
backgrounds: { value: 'gray', grid: false },
},
};
export const OnDark = {
globals: {
// 👇 Override background value for this story
backgrounds: { value: 'dark' },
},
};
需要特别注意:一旦通过 globals 为某个 Story 指定了 backgrounds.value,该颜色会被强制应用,无法再用工具栏切换。这正是 docs/essentials/backgrounds.mdx 中 Callout 提示强调的行为,适合用来保证回归测试或文档页中 Story 始终处于确定底色。若只是想设置“初始显示”的背景、同时保留用户在工具栏切换的自由度,应使用 initialGlobals(全局启动态)而不是 globals。
周边配置速查:disable、grid 与完整 API
理解 preview 配置后,Backgrounds 命名空间下还有几个同源参数常与 options 搭配使用,详见 docs/essentials/backgrounds.mdx 的 API 段落。
disable
类型 boolean。置为 true 可关闭背景功能,典型用法是在某个 Story 上单独关闭,例如 docs/_snippets/addon-backgrounds-disabled.md 中的:
export const Large = {
parameters: {
backgrounds: { disable: true },
},
};
若需要在整个 Storybook 级别关闭该功能,建议在 main.* 的 addons 配置中处理而非逐文件配置 disable。在 code/core/src/backgrounds/decorator.ts 可以看到,disable 直接参与 shownBackground 计算,最终决定样式是否注入。
grid
背景网格用于快速核对组件对齐情况。网格没有额外配置也能工作,如需自定义可在 parameters.backgrounds.grid 中提供,可用属性包括:
| 属性 | 类型 | 说明 |
|---|---|---|
cellAmount |
number |
次要网格线数量,默认 5 |
cellSize |
number |
主要网格线尺寸,默认 20 |
disable |
boolean |
关闭网格 |
offsetX / offsetY |
number |
网格偏移,默认在 fullscreen 布局下为 0、padded 布局下为 16(docs 模式下为 20) |
opacity |
number |
网格线透明度,默认 0.5 |
完整可运行的网格配置示例见 docs/_snippets/addon-backgrounds-grid.md。该参数与 options 一样支持在 preview、meta、story 各级配置。需要注意区分默认值:preview.ts 中插件声明层给出的网格默认值为 cellSize: 20 / opacity: 0.5 / cellAmount: 5(preview.ts),而装饰器内部用于兜底的 defaultGrid 为 cellSize: 100 / cellAmount: 10 / opacity: 0.8(decorator.ts),前者通常先于后者生效。
globals 与 parameters 完整类型
backgrounds 全局状态支持两种形态:{ value?: string; grid?: boolean } 或直接的 value 字符串;参数对象结构在 types.ts 中有完整 TypeScript 定义,含 default、disable、grid、options 四个可选字段,其中 default 用于声明默认背景键,options 即本文核心配置项。对比可以发现 docs 与源码在个别历史字段(如 default)上可能存在版本差异,以你所安装 Storybook 版本的导出类型为准。
如何验证配置是否生效
配置完成后,可借助仓库中已有的验证资源确认行为:
- Story 层面:参考模板 Story code/core/template/stories/backgrounds/globals.stories.ts,它演示了通过 globals 声明背景值的标准用法;
- 端到端测试:查看 code/e2e-sandbox/addon-backgrounds.spec.ts,了解 Playwright 如何断言背景色切换、网格展示与 docs 模式下背景注入等行为;
- 运行 Storybook 后在工具栏中展开背景下拉,确认自定义色名称(
name)与色值列表出现;切换选项后,检查画布容器background的计算样式是否等于对应value。
小结
在 .storybook/preview.* 中配置 Backgrounds 是让整个组件库统一背景规范的最直接手段:parameters.backgrounds.options 决定“有哪些背景可用”,initialGlobals.backgrounds.value 决定“启动时用哪一个”。若需要精确到组件或 Story 粒度,则可配合 parameters(改色板)与 globals(锁定背景)按层级覆写。结合 code/core/src/backgrounds/decorator.ts 的源码可以看出,这一切配置最终都收敛为一次“按 options 键查表 → 将 CSS 颜色注入预览容器”的简单而可预测的行为,理解这条链路之后,你就能从容定制出贴合团队设计规范的背景工作流。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00