主题
提取
🌐 Extracting
UnoCSS 的工作原理是通过在你的代码库中搜索工具类的使用情况,并按需生成相应的 CSS。我们称这个过程为 提取。
🌐 UnoCSS works by searching for utilities usage in your codebase and generating the corresponding CSS on-demand. We call this process extracting.
内容来源
🌐 Content Sources
UnoCSS 支持从多个来源提取工具用法:
🌐 UnoCSS supports extracting utilities usages from multiple sources:
来自不同来源的工具类的使用将会合并在一起,并生成最终的 CSS。
🌐 Usages of utilities that come from different sources will be merged together and generate the final CSS.
从构建工具管道中提取
🌐 Extracting from Build Tools Pipeline
🌐 This is supported in the Vite and Webpack integrations.
UnoCSS 会读取经过你的构建工具管道的内容,并从中提取工具类的使用情况。这是最高效且最准确的提取方式,因为我们只提取实际上在你的应用中使用的内容,并且在提取过程中不会进行额外的文件 I/O 操作。
🌐 UnoCSS will read the content that goes through your build tools pipeline and extract the utilities usages from it. This is the most efficient and accurate way to extract, as we only extract the usages that are actually used in your app, smartly, with no additional file I/O made during the extraction.
默认情况下,UnoCSS 会从构建流程中扩展名为 .jsx、.tsx、.vue、.md、.html、.svelte、.astro、.marko 的文件中提取工具类的使用情况,然后按需生成相应的 CSS。.js 和 .ts 文件 默认不包括。
🌐 By default, UnoCSS will extract the utilities usage from files in your build pipeline with extensions .jsx, .tsx, .vue, .md, .html, .svelte, .astro, .marko, and then generate the appropriate CSS on demand. .js and .ts files are NOT included by default.
要配置它们,你可以更新你的 uno.config.ts:
🌐 To configure them, you can update your uno.config.ts:
ts
export default defineConfig({
content: {
pipeline: {
include: [
// the default
/\.(vue|svelte|[jt]sx|vine.ts|mdx?|astro|elm|php|phtml|marko|html)($|\?)/,
// include js/ts files
'src/**/*.{js,ts}',
],
// exclude files
// exclude: []
},
},
})你还可以在每个文件的任意位置添加 @unocss-include 魔法注释,让 UnoCSS 扫描。如果你需要扫描 *.js 或 *.ts 文件,可以在配置中添加它们,将所有 js/ts 文件包含为扫描目标。
🌐 You can also add @unocss-include magic comment, on a per-file basis, anywhere in the file that you want UnoCSS to scan. If you need to scan *.js or *.ts files, add them in the configuration to include all js/ts files as scan targets.
ts
// ./some-utils.js
// since `.js` files are not included by default,
// the following comment tells UnoCSS to force scan this file.
// @unocss-include
export const classes = {
active: 'bg-primary text-white',
inactive: 'bg-gray-200 text-gray-500',
}同样,你也可以添加 @unocss-ignore 来跳过整个文件的扫描和转换。
🌐 Similarly, you can also add @unocss-ignore to bypass the scanning and transforming for the whole file.
如果你希望 UnoCSS 跳过一段代码,不在任何提取的文件中被提取,可以成对使用 @unocss-skip-start 和 @unocss-skip-end。注意,它必须成对使用才能生效。
🌐 If you want the UnoCSS to skip a block of code without being extracted in any extracting files, you can use @unocss-skip-start and @unocss-skip-end in pairs. Note that it must be used in pairs to be effective.
html
<p class="text-green text-xl">Green Large</p>
<!-- @unocss-skip-start -->
<!-- `text-red` will not be extracted -->
<p class="text-red">Red</p>
<!-- @unocss-skip-end -->从文件系统中提取
🌐 Extracting from Filesystem
在你使用无法访问构建工具管道的集成(例如,PostCSS 插件),或者你与后端框架集成以致代码不经过管道的情况下,你可以手动指定要提取的文件。
🌐 In cases that you are using integrations that do not have access to the build tools pipeline (for example, the PostCSS plugin), or you are integrating with backend frameworks such that the code does not go through the pipeline, you can manually specify the files to be extracted.
ts
export default defineConfig({
content: {
filesystem: [
'src/**/*.php',
'public/*.html',
],
},
})匹配的文件将直接从文件系统读取,并在开发模式下监视更改。
🌐 The files matched will be read directly from the filesystem and watched for changes at dev mode.
从内嵌文本中提取
🌐 Extracting from Inline Text
此外,你还可以从其他地方获取的内联文本中提取工具的使用情况。
🌐 Additionally, you can also extract utility usages from inline text that you might retrieve from elsewhere.
你也可以传入一个异步函数来返回内容,但请注意,该函数只会在构建时调用一次。
🌐 You may also pass an async function to return the content. But note that the function will only be called once at build time.
ts
export default defineConfig({
content: {
inline: [
// plain text
'<div class="p-4 text-red">Some text</div>',
// async getter
async () => {
const response = await fetch('https://example.com')
return response.text()
},
],
},
})局限性
🌐 Limitations
由于 UnoCSS 在构建时工作,这意味着只有静态呈现的工具类会被生成并打包到你的应用中。在运行时动态使用或从外部资源获取的工具类可能无法被检测或应用。
🌐 Since UnoCSS works at build time, it means that only statically presented utilities will be generated and shipped to your app. Utilities that are used dynamically or fetched from external resources at runtime might NOT be detected or applied.
安全列表
🌐 Safelist
有时你可能想使用动态串联,例如:
🌐 Sometimes you might want to use dynamic concatenations like:
html
<div class="p-${size}"></div>
<!-- this won't work! -->由于 UnoCSS 在构建时使用静态提取,因此在编译时它不可能知道所有的工具类组合。为此,你可以配置 safelist 选项。
🌐 Due to the fact that UnoCSS works in build time using static extraction, at compile time it can't possibly know all the combinations of the utilities then. For that, you can configure the safelist option.
ts
safelist: 'p-1 p-2 p-3 p-4'.split(' ')总是会生成相应的 CSS:
🌐 The corresponding CSS will always be generated:
css
.p-1 { padding: 0.25rem; }
.p-2 { padding: 0.5rem; }
.p-3 { padding: 0.75rem; }
.p-4 { padding: 1rem; }或者更灵活:
🌐 Or more flexible:
ts
safelist: [
...Array.from({ length: 4 }, (_, i) => `p-${i + 1}`),
]如果你正在寻找真正的运行时动态生成,可能想看看 @unocss/runtime 包。
🌐 If you are seeking a true dynamic generation at runtime, you may want to check out the @unocss/runtime package.
静态列表组合
🌐 Static List Combinations
绕过动态构建工具限制的另一种方法是,你可以使用一个静态列出所有组合的对象。例如,如果你想要这样做:
🌐 Another way to work around the limitation of dynamically constructed utilities is that you can use an object that lists all the combinations statically. For example, if you want to have this:
html
<div class="text-${color} border-${color}"></div>
<!-- this won't work! -->你可以创建一个对象,列出所有组合(假设你知道你想使用的 color 的任何可能值)
🌐 You can create an object that lists all the combinations (assuming you know any possible values of color you want to use)
ts
// Since they are static, UnoCSS will be able to extract them at build time
const classes = {
red: 'text-red border-red',
green: 'text-green border-green',
blue: 'text-blue border-blue',
}然后在你的模板中使用它:
🌐 And then use it in your template:
html
<div class="${classes[color]}"></div>黑名单
🌐 Blocklist
与 safelist 类似,你也可以配置 blocklist 来排除某些工具的生成。这对于防止提取误报非常有用。
🌐 Similar to safelist, you can also configure blocklist to exclude some utilities from being generated. This is useful for preventing extraction false positives.
但是,黑名单远比简单的排除列表强大得多。在拥有众多贡献者的大型项目中,UnoCSS 的灵活性——同样的视觉效果可以通过多种实用语法实现——反而可能成为一种负担。不同的开发者可能会为了生成相同的 CSS 输出而写 border、border-1 或 b,这会导致生成的样式表中出现重复规则、在代码审查中出现不一致,并且 CSS 包体积不断增加。黑名单允许你通过阻止冗长或非标准的替代写法,并引导开发者使用首选形式,从而在整个代码库中强制使用统一的规范语法。结合 @unocss/eslint-plugin 使用,它就像一个自动化的样式指南,限制实用类使用设计系统的标记,强制使用最短的别名,并阻止任意值——在保持 CSS 输出最小化的同时,确保大型项目的代码库保持一致性。
🌐 But the blocklist is far more powerful than a simple exclusion list. In large-scale projects with many contributors, UnoCSS's flexibility — where the same visual result can be achieved with multiple utility syntaxes — becomes a liability. Different developers might write border, border-1, or b for the same CSS output, resulting in duplicate rules in the generated stylesheet, inconsistent code during reviews, and a growing CSS bundle. The blocklist lets you enforce a single canonical syntax across the entire codebase by blocking verbose or non-standard alternatives and pointing developers to the preferred form. Combined with @unocss/eslint-plugin, it acts as an automated style guide that restricts utilities to design system tokens, enforces the shortest aliases, and prevents arbitrary values — keeping CSS output minimal and the codebase consistent at scale.
匹配器类型
🌐 Matcher Types
blocklist 接受三种匹配器类型:
🌐 The blocklist accepts three matcher types:
字符串 — 精确匹配:
ts
blocklist: [
'p-1', // blocks p-1 exactly
'tab', // blocks tab exactly
]RegExp — 模式匹配(使用 .test()):
ts
blocklist: [
/^p-[2-4]$/, // blocks p-2, p-3, p-4
/^border$/, // blocks "border" but not "border-2"
]函数 — 自定义逻辑,返回真值以阻止:
ts
blocklist: [
s => s.endsWith('px'), // block all px-suffixed classes
s => s.split('-').length > 4, // block deeply nested utilities
]消息
🌐 Messages
每个匹配器可以选择性地被封装在一个元组中,该元组包含一个 message,用于解释该工具被阻止的原因。该消息可以是静态字符串,或是接收匹配的选择器的回调函数:
🌐 Each matcher can optionally be wrapped in a tuple containing a message that explains why the utility is blocked. The message can be a static string or a callback that receives the matched selector:
ts
blocklist: [
// static message
[/^border$/, { message: 'use shorter "b"' }],
// dynamic message — receives the blocked selector
[/^border(?:-[btrlxy])?$/, {
// e.g. "border-y" → 'use shorter "b-y"'
message: v => `use shorter "${v.replace(/^border/, 'b')}"`
}],
]当与 @unocss/eslint-plugin 一起使用时,消息会出现在 lint 输出中:
🌐 When used with @unocss/eslint-plugin, the message appears in lint output:
"border" is in blocklist: use shorter "b"如果没有 ESLint 插件,被阻止的工具会在生成 CSS 时被静默排除,开发者不会收到任何反馈。 建议在使用阻止列表规则时搭配 @unocss/eslint-plugin,以在开发过程中显示可操作的提示信息。
🌐 Without the ESLint plugin, blocked utilities are silently excluded from CSS generation with no feedback to the developer. It is recommended to use @unocss/eslint-plugin alongside blocklist rules to surface actionable messages during development.
变体意识
🌐 Variant Awareness
黑名单会在变体剥离前后检查选择器。 阻止 p-1 的规则也会阻止 hover:p-1、md:p-1、dark:p-1 等。 在黑名单模式中,你无需考虑变体前缀。
🌐 The blocklist checks selectors both before and after variant stripping. A rule blocking p-1 will also block hover:p-1, md:p-1, dark:p-1, etc. You don't need to account for variant prefixes in your blocklist patterns.
合并行为
🌐 Merging Behavior
来自所有预设和用户配置的黑名单数组会合并——它们会累积,并且永远不会互相覆盖。任何被某个预设或用户配置阻止的工具都会继续被阻止。
🌐 Blocklist arrays from all presets and the user config are merged — they accumulate and never override each other. A utility blocked by any preset or the user config will remain blocked.
类型引用
🌐 Type Reference
ts
type BlocklistValue = string | RegExp | ((selector: string) => boolean | null | undefined)
type BlocklistRule = BlocklistValue | [BlocklistValue, BlocklistMeta]
interface BlocklistMeta {
/**
* Custom message to show why this selector is blocked.
*/
message?: string | ((selector: string) => string)
}阻止列表模式
🌐 Blocklist Patterns
以下是有效使用黑名单的常见模式。
🌐 Below are common patterns for using the blocklist effectively.
强制使用更短的别名
🌐 Enforcing Shorter Aliases
当 UnoCSS 支持针对同一 CSS 输出使用多种语法时,你可以屏蔽冗长的形式并建议使用更简短的形式:
🌐 When UnoCSS supports multiple syntaxes for the same CSS output, you can block the verbose form and suggest the shorter one:
ts
blocklist: [
// "border" → "b", "border-t" → "b-t"
[/^border(?:-[btrlxy])?$/, {
message: v => `use shorter "${v.replace(/^border/, 'b')}"`
}],
// "opacity-50" → "op-50"
// "backdrop-opacity-50" → "backdrop-op-50"
[/^(?:backdrop-)?opacity-(.+)$/, {
message: v => `use shorter "${v.replace(/opacity-/, 'op-')}"`
}],
// "whitespace-nowrap" → "ws-nowrap"
[/^whitespace-.+$/, {
message: v => `use shorter "${v.replace(/^whitespace-/, 'ws-')}"`
}],
// simple static aliases work well for one-to-one replacements
[/^flex-grow$/, { message: 'use shorter "grow"' }],
[/^flex-shrink$/, { message: 'use shorter "shrink"' }],
[/^inline-block$/, { message: 'use shorter "i-block"' }], // you can point to your custom shortcuts as well
]限制为设计系统令牌
🌐 Restricting to Design System Tokens
你可以根据设计系统配置动态构建黑名单模式,以确保仅使用有效的标记。使用负向前瞻允许有效值,同时阻止其他所有值:
🌐 You can dynamically build blocklist patterns from your design system config to ensure only valid tokens are used. Use a negative lookahead to permit valid values while blocking everything else:
ts
import { theme } from './my-design-system'
// Helper to join object keys into a regex alternation
const keys = (obj: Record<string, any>) => Object.keys(obj).join('|')
blocklist: [
// Only allow font families defined in the design system
[new RegExp(`^font-(?!(?:${keys(theme.fontFamily)}|\\$)$).+$`), {
message: `use design system font families: ${Object.keys(theme.fontFamily).join(', ')}`
}],
// Only allow shadow values from the design system
[new RegExp(`^shadow-(?!(?:${keys(theme.boxShadow)}|\\$)).+$`), {
message: `only design system shadow values are allowed.`
}],
]TIP
负向前瞻中的 \\$ 允许 CSS 变量引用(例如 font-$myVar)通过,因为这些在运行时解析,无法进行静态验证。
将原始单位转换为标度值
🌐 Converting Raw Units to Scale Values
如果你的项目使用 UnoCSS 默认的间距刻度(其中 1 单位 = 0.25rem = 4px),你可以屏蔽原始的 px 和 rem 值,并建议使用刻度等效值:
🌐 If your project uses the UnoCSS default spacing scale (where 1 unit = 0.25rem = 4px), you can block raw px and rem values and suggest the scale equivalent:
ts
blocklist: [
// "mt-16px" → "mt-4"
// "p-[8px]" → "p-2"
// "w-2rem" → "w-8"
[/^.+-\[?[\d.]+(?:px|rem)\]?$/, {
message: (s) => {
// since message() only receives the matched selector string, not the regex
// we have to match it again to extract capture groups from the blocklist matcher
const m = s.match(/\[?(?<v>[\d.]+)(?<u>px|rem)\]?$/)!
const { v, u } = m.groups!
const scale = u === 'rem' ? +v * 4 : +v / 4
return `use spacing scale value: ${s.slice(0, -m[0].length)}${scale}`
}
}],
]去掉不必要的括号
🌐 Removing Unnecessary Brackets
当值本身已经有效时,UnoCSS 任意值括号 [...] 通常是不必要的:
🌐 UnoCSS arbitrary value brackets [...] are often unnecessary when the value is already valid without them:
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 `use shorter ${v.replace(/-\[\d+%\]/, `-${value}`)}`
}
}],
// "outline-[#ff0000]" → "outline-#ff0000"
[/^[a-z-]+-\[#[0-9a-fA-F]{3,6}\]$/, {
message: v => `use shorter ${v.replace(/\[#/, '#').replace(/\]/, '')}`
}],
]执行惯例
🌐 Enforcing Conventions
阻止违反项目特定架构决策的模式:
🌐 Block patterns that violate project-specific architectural decisions:
ts
blocklist: [
// Prevent redundant breakpoint — if "sm" equals 0, it's always active
// in mobile-first responsive design and should not be specified
[/^sm:/, {
message: v => `sm: breakpoint is redundant, use "${v.replace(/^sm:/, '')}"`
}],
// Force separate utility classes instead of slash opacity notation.
// Separate utilities have a higher chance of reuse than slashed combinations,
// which helps reduce the resulting CSS bundle size
// "bg-red-500/50" → "bg-red-500 bg-op-50"
[/^(c|bg)-.+\/\d+$/, {
message: 'use separate opacity class instead of slash notation (e.g., "bg-red bg-op-50").'
}],
// Decompose shorthands into reusable individual properties.
// Same principle — separate utilities reduce CSS bundle size
// "size-4" → "w-4 h-4"
[/^size-(.+)$/, {
message: (v) => {
const size = v.match(/^size-(.+)$/)?.[1]
return `use "w-${size} h-${size}" for independent control`
}
}],
]