--- url: https://unocss.zhcndoc.com/guide/extracting.md --- # 提取 UnoCSS 通过在你的代码库中搜索工具的使用,按需生成相应的 CSS。我们称这一过程为 **提取**。 ## 内容来源 UnoCSS 支持从多个来源提取工具的使用: * [构建工具管道](#从构建工具管道提取) - 直接从构建工具管道中提取 * [文件系统](#从文件系统提取) - 通过读取和监视文件从文件系统中提取 * [内联](#从内联文本提取) - 从内联纯文本中提取 来自不同来源的工具使用将合并在一起,生成最终的 CSS。 ### 从构建工具管道提取 这在 [Vite](/integrations/vite) 和 [Webpack](/integrations/webpack) 集成中受支持。 UnoCSS 将读取经过构建工具管道的内容,并从中提取工具的使用。这是提取的最有效和准确的方法,因为我们仅智能地提取在你的应用中实际使用的工具,且提取过程中不进行额外的文件 I/O 操作。 默认情况下,UnoCSS 会从构建流程中的 `.jsx`、`.tsx`、`.vue`、`.md`、`.html`、`.svelte`、`.astro`、`.marko` 等扩展名的文件中提取工具类的使用,并按需生成相应的 CSS。`.js` 和 `.ts` 文件**默认不包含**。 要配置它们,你可以更新你的 `uno.config.ts`: ```ts [uno.config.ts] export default defineConfig({ content: { pipeline: { include: [ // 默认 /\.(vue|svelte|[jt]sx|vine.ts|mdx?|astro|elm|php|phtml|marko|html)($|\?)/, // 包括 js/ts 文件 'src/**/*.{js,ts}', ], // 排除文件 // exclude: [] }, }, }) ``` 你还可以在需要 UnoCSS 扫描的文件中的任意位置添加 `@unocss-include` 魔法注释,以逐个文件为单位。这对于需要扫描 `*.js` 或 `*.ts` 文件时尤其有用,需在配置中包含所有 js/ts 文件作为扫描目标。 ```ts // ./some-utils.js // 由于 `.js` 文件未默认包含, // 以下注释告知 UnoCSS 强制扫描此文件。 // @unocss-include export const classes = { active: 'bg-primary text-white', inactive: 'bg-gray-200 text-gray-500', } ``` 同样,你也可以添加 `@unocss-ignore` 来跳过整个文件的扫描和转换。 如果你想让 UnoCSS 跳过一块代码而不在任何提取文件中被提取,你可以使用 `@unocss-skip-start` 和 `@unocss-skip-end` 作为成对使用。请注意,它必须 **成对使用** 才能生效。 ```html

绿色大号

红色

``` ### 从文件系统提取 在使用没有访问构建工具管道的集成的情况下(例如 [PostCSS](/integrations/postcss) 插件),或者在与后端框架集成时,因为代码没有经过管道,你可以手动指定要提取的文件。 ```ts [uno.config.ts] export default defineConfig({ content: { filesystem: [ 'src/**/*.php', 'public/*.html', ], }, }) ``` 符合条件的文件将直接从文件系统读取,并在开发模式下监视其变化。 ### 从内联文本提取 此外,你还可以从可能从其他地方检索到的内联文本中提取工具的使用。 你也可以传递一个异步函数以返回内容。但请注意,该函数将在构建时只调用一次。 ```ts [uno.config.ts] export default defineConfig({ content: { inline: [ // 纯文本 '
一些文本
', // 异步获取器 async () => { const response = await fetch('https://example.com') return response.text() }, ], }, }) ``` ## 限制 由于 UnoCSS 在 **构建时** 工作,这意味着只有静态呈现的工具将被生成并打包到你的应用中。动态使用或在运行时从外部资源获取的工具可能 **不会** 被检测或应用。 ### 安全列表 有时你可能想使用动态连接,例如: ```html
``` 由于 UnoCSS 在构建时使用静态提取,因此在编译时它无法知道所有工具的组合。为此,你可以配置 `safelist` 选项。 ```ts [uno.config.ts] safelist: 'p-1 p-2 p-3 p-4'.split(' ') ``` 对应的 CSS 将始终生成: ```css .p-1 { padding: 0.25rem; } .p-2 { padding: 0.5rem; } .p-3 { padding: 0.75rem; } .p-4 { padding: 1rem; } ``` 或者更灵活地: ```ts [uno.config.ts] safelist: [ ...Array.from({ length: 4 }, (_, i) => `p-${i + 1}`), ] ``` 如果你寻求在运行时进行真正的动态生成,你可能需要查看 [@unocss/runtime](/integrations/runtime) 包。 ### 静态列表组合 解决动态构造工具限制的另一种方法是,你可以使用一个对象列出所有组合 **静态**。例如,如果你想要这个: ```html
``` 你可以创建一个对象,列出所有组合(假设你知道想要使用的 `color` 的所有可能值) ```ts // 由于它们是静态的,UnoCSS 将能够在构建时提取它们 const classes = { red: 'text-red border-red', green: 'text-green border-green', blue: 'text-blue border-blue', } ``` 然后在你的模板中使用它: ```html
``` ### 黑名单 类似于 `safelist`,你也可以配置 `blocklist` 以排除一些工具的生成。这对于排除一些提取的误报非常有用。与 `safelist` 不同,`blocklist` 同时接受字符串以进行精确匹配和正则表达式以进行模式匹配。 ```ts [uno.config.ts] blocklist: [ 'p-1', // 精确匹配并阻止 p-1 'tab', // 精确匹配并阻止 tab ] ``` 这将排除 `p-1` 以及 `p-2`、`p-3`、`p-4` 的生成。 **正则表达式** — 模式匹配(使用 `.test()`): ```ts [uno.config.ts] blocklist: [ /^p-[2-4]$/, // 阻止 p-2、p-3、p-4 /^border$/, // 阻止 "border" 但不阻止 "border-2" ] ``` **函数** — 自定义逻辑,返回真值即阻止: ```ts [uno.config.ts] blocklist: [ s => s.endsWith('px'), // 阻止所有以 px 结尾的类名 s => s.split('-').length > 4, // 阻止嵌套层级过深的工具类 ] ``` #### 消息提示 每个匹配器可以可选地用一个包含说明阻止原因的 `message` 的元组包装。消息可以是静态字符串,也可以是接收被匹配选择器的回调: ```ts [uno.config.ts] blocklist: [ // 静态消息 [/^border$/, { message: '请使用更短的 "b"' }], // 动态消息 — 接收被阻止的选择器 [/^border(?:-[btrlxy])?$/, { // 例如 "border-y" → '请使用更短的 "b-y"' message: v => `请使用更短的 "${v.replace(/^border/, 'b')}"` }], ] ``` 与 `@unocss/eslint-plugin` 配合使用时,消息会显示在 lint 输出中: ```shell "border" 在黑名单中:请使用更短的 "b" ``` 如果没有 ESLint 插件,被阻止的工具类将静默地从 CSS 生成中排除,开发者不会收到反馈。 **建议结合使用 `@unocss/eslint-plugin` 和 blocklist 规则**,以便在开发期间显示可操作的消息。 #### 变体处理 黑名单会在 **去除变体之前和之后** 检查选择器。 阻止 `p-1` 的规则也会阻止 `hover:p-1`、`md:p-1`、`dark:p-1` 等。 你不需要在黑名单模式中考虑变体前缀。 #### 合并行为 所有预设和用户配置的黑名单规则会被 **合并** — 它们会累积,不会相互覆盖。 任何在任一预设或用户配置中被阻止的工具都会保持被阻止状态。 #### 类型参考 ```ts type BlocklistValue = string | RegExp | ((selector: string) => boolean | null | undefined) type BlocklistRule = BlocklistValue | [BlocklistValue, BlocklistMeta] interface BlocklistMeta { /** * 用于显示阻止原因的自定义消息。 */ message?: string | ((selector: string) => string) } ``` ### 黑名单模式示例 以下是一些常见的黑名单使用模式,帮助你更有效地使用黑名单。 #### 强制使用更简短的别名 由于 UnoCSS 支持多种语法实现相同的 CSS 输出,你可以阻止冗长形式,推荐更简洁的形式: ```ts [uno.config.ts] blocklist: [ // "border" → "b", "border-t" → "b-t" [/^border(?:-[btrlxy])?$/, { message: v => `请使用更短的 "${v.replace(/^border/, 'b')}"` }], // "opacity-50" → "op-50" // "backdrop-opacity-50" → "backdrop-op-50" [/^(?:backdrop-)?opacity-(.+)$/, { message: v => `请使用更短的 "${v.replace(/opacity-/, 'op-')}"` }], // "whitespace-nowrap" → "ws-nowrap" [/^whitespace-.+$/, { message: v => `请使用更短的 "${v.replace(/^whitespace-/, 'ws-')}"` }], // 简单的静态别名非常适合一一替换 [/^flex-grow$/, { message: '请使用更短的 "grow"' }], [/^flex-shrink$/, { message: '请使用更短的 "shrink"' }], [/^inline-block$/, { message: '请使用更短的 "i-block"' }], // 你也可以指向自定义快捷方式 ] ``` #### 限制为设计系统的令牌 你可以根据设计系统配置动态生成黑名单模式,确保只使用有效令牌。 使用负向前瞻来允许有效值,其它全部阻止: ```ts [uno.config.ts] import { theme } from './my-design-system' // 辅助函数,将对象的键连接成正则表达式的或匹配 const keys = (obj: Record) => Object.keys(obj).join('|') blocklist: [ // 仅允许设计系统中定义的字体系列 [new RegExp(`^font-(?!(?:${keys(theme.fontFamily)}|\\$)$).+$`), { message: `请使用设计系统字体系列:${Object.keys(theme.fontFamily).join(', ')}` }], // 仅允许设计系统中定义的阴影值 [new RegExp(`^shadow-(?!(?:${keys(theme.boxShadow)}|\\$)).+$`), { message: `只允许使用设计系统的阴影值。` }], ] ``` ::: tip 正则中的 `\\$` 允许 CSS 变量引用(例如 `font-$myVar`)通过,因为它们在运行时解析,无法静态验证。 ::: #### 将原生单位转换为刻度值 如果你的项目使用 UnoCSS 默认的间距刻度(1 单位 = 0.25rem = 4px),你可以阻止原生的 `px` 和 `rem` 值,并建议使用刻度等价的值: ```ts [uno.config.ts] blocklist: [ // "mt-16px" → "mt-4" // "p-[8px]" → "p-2" // "w-2rem" → "w-8" [/^.+-\[?[\d.]+(?:px|rem)\]?$/, { message: (s) => { // 由于 message() 只接受匹配的选择器字符串,而不接受正则表达式, // 所以需要再次匹配以提取捕获组 const m = s.match(/\[?(?[\d.]+)(?px|rem)\]?$/)! const { v, u } = m.groups! const scale = u === 'rem' ? +v * 4 : +v / 4 return `请使用间距刻度值:${s.slice(0, -m[0].length)}${scale}` } }], ] ``` #### 移除不必要的方括号 UnoCSS 的任意值括号 `[...]` 经常不必要,当值本身已经合法时可以省略: ```ts [uno.config.ts] blocklist: [ // "w-[50%]" → "w-50%" [/^(w|h|min-[wh]|max-[wh]|top|right|bottom|left)-\[\d+%\]$/, { message: (v) => { const value = v.match(/\[(\d+%)\]/)?.[1] || '' return `请使用更简短的 ${v.replace(/-\[\d+%\]/, `-${value}`)}` } }], // "outline-[#ff0000]" → "outline-#ff0000" [/^[a-z-]+-\[#[0-9a-fA-F]{3,6}\]$/, { message: v => `请使用更简短的 ${v.replace(/\[#/, '#').replace(/\]/, '')}` }], ] ``` #### 强制约定 阻止违反项目特定架构决策的模式: ```ts [uno.config.ts] blocklist: [ // 防止冗余断点 — 如果 "sm" 等于 0,则它总是生效 // 在移动优先响应设计中应避免指定 [/^sm:/, { message: v => `sm: 断点是冗余的,请使用 "${v.replace(/^sm:/, '')}"` }], // 强制使用分离的工具类,而非斜杠不透明度标记。 // 分离的工具类更可能重用,帮助减少最终 CSS 包大小 // "bg-red-500/50" → "bg-red-500 bg-op-50" [/^(c|bg)-.+\/\d+$/, { message: '请使用分离的透明度类代替斜杠标记(例如 "bg-red bg-op-50")。' }], // 将简写拆解为可重用的独立属性。 // 同理,分离工具类有助于减少 CSS 包大小 // "size-4" → "w-4 h-4" [/^size-(.+)$/, { message: (v) => { const size = v.match(/^size-(.+)$/)?.[1] return `请使用 "w-${size} h-${size}" 来独立控制` } }], ] ```