☰
Storybook 全局样式注入指南:通过 preview-head.html 加载字体与全局 CSS
2026/9/25 13:01:41 网站建设 项目流程

Storybook 全局样式注入指南:通过 preview-head.html 加载字体与全局 CSS

【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook

在 Storybook 中,组件渲染在独立的预览 iframe(Canvas)内,默认不加载你业务项目里的全局样式。本文以 storybook-preview-head-import-global-styles.md 为核心,讲解如何通过.storybook/preview-head.html将 CDN 字体、自定义 CSS 等资源注入预览 iframe 的<head>,让每个 story 都以真实项目样式渲染。读完你将掌握:preview-head.html 的文件位置与写法、与previewHead预设和preview-body.html的配合方式,以及注入内容的作用域边界与调试方法。

一、为什么需要 preview-head.html:预览 iframe 的样式隔离

Storybook 是一个用于在隔离环境中构建、文档化和测试 UI 组件的 workshop(见仓库根目录 README.md)。它的故事(stories)渲染在名为 Canvas 的“预览 iframe”中,而 Storybook 应用本身的 UI(Manager)与 iframe 是两个独立的文档(详见 story-rendering.mdx)。

这意味着:你在业务项目index.html或全局 CSS 中定义的样式、加载的字体,不会自动出现在预览 iframe 里。要让组件在 Storybook 中以接近真实项目的方式渲染,就需要把需要的资源显式注入到 iframe 的<head>。官方文档在 styling-and-css.mdx 中明确指出:如果有希望在所有 stories 中生效的全局 CSS 文件,可以把它引入到.storybook/preview-head.html中——这正是本文主角场景的出处。

二、核心配置:preview-head.html 的写法

在.storybook目录下创建preview-head.html,把需要注入<head>的标签写进去即可。官方 snippet 给出了一个同时加载 CDN 字体与本地 CSS 的完整示例:

<!-- Loads a font from a CDN --> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap" rel="stylesheet" /> <!-- Load your CSS file --> <link rel="stylesheet" href="path/to/your/styles.css" />

写法要点拆解

  • rel="preconnect"预热连接:对fonts.googleapis.com与fonts.gstatic.com提前建立连接(后者带crossorigin),能显著缩短字体样式表与字体文件的加载延迟。
  • family=Inter:wght@100..900:Google Fonts 的 CSS2 API 语法,100..900表示加载从细到粗的整个可变字重区间,供组件在不同字重下验证效果。
  • <link rel="stylesheet">引入本地 CSS:path/to/your/styles.css需按实际情况替换(详见下文“静态资源路径”一节)。

扩展示例:预加载本地字体与自定义脚本

官方 storybook-preview-head-example.md 还展示了预加载本地字体与注入自定义 head 脚本的写法:

<!-- Pull in static files served from your Static directory or the internet Example: `main.js|ts` is configured with staticDirs: ['../public'] and your font is located in the `fonts` directory inside your `public` directory --> <link rel="preload" href="/fonts/my-font.woff2" /> <!-- Or you can load custom head-tag JavaScript: --> <script src="https://use.typekit.net/xxxyyy.js"></script> <script> try { Typekit.load(); } catch (e) {} </script>

三、静态资源路径:staticDirs 与相对路径

在 preview-head.html 中引用本地资源时,路径解析遵循以下规则:

  • 托管在 Storybook 静态目录中的文件:在main.js|ts中通过staticDirs: ['../public']配置静态目录后,preview-head.html 里可用根路径(如/fonts/my-font.woff2)直接引用,这与官方 snippet 注释中的示例一致。静态文件目录的完整配置说明见 images-and-assets.mdx。
  • 仓库内相对路径:<link rel="stylesheet" href="path/to/your/styles.css" />中的路径按你项目结构替换为相对路径或可访问的 URL。

四、作用域边界:注入的是预览 iframe,不是 Storybook UI

官方在 story-rendering.mdx 中用醒目提示强调:Storybook 会把preview-head.html中的标签注入到组件渲染所在的预览 iframe,而不是 Storybook 应用界面。

理解这条边界很重要:

  • 你的全局样式会作用于所有 stories 的渲染结果,保证 Canvas 中的组件观感与真实项目一致;
  • Storybook 自身的工具栏、侧边栏等 Manager UI 不会受影响;
  • 因此,把 reset、设计 token、字体族等“业务全局样式”放进 preview-head.html 是正确做法,而不要指望它去改变 Storybook 界面主题(界面主题由 addon-themes 等其他机制处理)。

五、程序化方案:main.js 中的 previewHead 预设

如果不需要静态注入,而是想按环境或条件程序化地修改预览<head>,官方提供了previewHead预设(类型(head: string) => string),定义在 main-config-preview-head.mdx 中。官方示例:仅在设置了ANALYTICS_ID环境变量时注入统计脚本:

export default { framework: '@storybook/your-framework', stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], previewHead: (head) => ` ${head} ${ process.env.ANALYTICS_ID ? '<script src="https://cdn.example.com/analytics.js"></script>' : '' } `, };

(TypeScript 项目可改用main.ts并搭配import type { StorybookConfig } from '@storybook/your-framework';,见 main-config-preview-head.md 中的完整变体。)

该预设多数场景由 addon 作者 在 UI 配置阶段使用;如果你只是加载静态字体和样式,优先选择preview-head.html即可,官方文档也给出了同样的建议。

从源码实现看,该能力由 core-server 的 common-preset.ts 提供:previewHead预设会结合configDir读取preview-head.html模板,并对环境变量插值(getPreviewHeadTemplate(configDir, interpolations))后注入预览页面。也就是说,两种方式最终都汇入同一条渲染管线,模板中的占位与程序化追加的内容都会被合并进预览 iframe 的 head。

六、配套能力:preview-body.html 与全局样式导入

除了<head>,官方还提供了对称的preview-body.html注入机制(见 story-rendering.mdx),适用于需要向<body>添加自定义内容根节点的场景。例如,项目使用rem/em相对单位时,可通过它调整基准字号:

<style> html { font-size: 15px; } </style>

另外,若你使用 Angular 框架,官方还提供了通过angular.json的styles数组添加全局样式的方案(见 styling-and-css.mdx),注意同时同步到build-storybooktarget,确保静态构建产物也包含这些样式——这与 preview-head.html 是互补的两条路径。

七、实践清单与调试建议

  1. 确认文件位置:preview-head.html必须位于.storybook目录下,与main.js|ts、preview.ts|tsx同级。
  2. 按需加载:CDN 字体适合验证用字体渲染的组件;生产或离线环境建议把字体文件放入 staticDirs 目录后本地引用。
  3. 检查注入结果:启动storybook dev后,打开任意 story 的 Canvas,在开发者工具中查看 iframe 内的<head>,确认 link/script 标签已注入、网络请求无 404。
  4. 区分注入目标:样式只进预览 iframe;若想改动 Storybook 界面,请走 Manager 侧的主题/Manager 配置机制。
  5. 组合使用:静态注入用preview-head.html,条件注入(如按环境变量)用previewHead预设,二者可以并存。

总结

.storybook/preview-head.html是 Storybook 向预览 iframe 注入全局字体、CSS 与脚本的官方入口,与previewHead预设、preview-body.html共同构成完整的预览 HTML 定制体系。通过本文的示例与源码印证,你可以让每个 story 在接近真实项目的样式环境下渲染,同时清晰把握注入的作用域边界,避免样式污染 Storybook 自身界面。

【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询