addUtilities是唯一安全注入自定义工具类的API;必须用tailwindcss/plugin包裹,仅支持扁平对象,响应式与深色模式需手动展开,动态类名应使用matchUtilities,且content必须覆盖所有使用路径。

直接在 CSS 文件里写 .my-class { } 不生效,不是 Tailwind 的 bug,是它按需生成机制的正常行为——类名没在 content 路径下出现过,就不会被打包进最终 CSS。
用 addUtilities 注入工具类才是唯一安全方式
手写 CSS、裸对象导出、或裸函数调用 addUtilities 都会破坏构建流程,只有被 tailwindcss/plugin 包裹的函数才可用 addUtilities 和 theme()。
- ❌ 错误写法:
module.exports = { '.sr-only': { position: 'absolute' } } - ❌ 错误写法:
module.exports = ({ addUtilities }) => { addUtilities({}) } - ✅ 正确写法:
const plugin = require('tailwindcss/plugin'); module.exports = plugin(({ addUtilities }) => { addUtilities({ '.sr-only': { position: 'absolute', clip: 'rect(0 0 0 0)' } }) }) -
addUtilities只接受扁平对象,不支持&:hover或嵌套结构;需要变体支持(如hover:)必须手动展开,或改用addComponents
让自定义类支持响应式和 dark 模式要手动展开
Tailwind 不会自动给你的自定义类加上响应式前缀或深色模式逻辑,你得自己写全。
- 响应式:用媒体查询键,注意冒号要双反斜杠转义,例如
'@media (min-width: 768px)': { '.md\:sr-only': { ... } }' -
dark模式:必须显式组合选择器,如'.dark .dark\:bg-brand': { backgroundColor: theme('colors.brand.500') } -
theme()只能读取theme.extend中已声明的路径,比如没在extend.colors.brand里定义,theme('colors.brand.500')就返回undefined
需要动态值(如 text-2.5rem)就用 matchUtilities
硬编码所有可能的组合既不可维护,也不符合 JIT 编译逻辑。
立即学习“前端免费学习笔记(深入)”;
- 匹配正则提取值,例如
/^text-([d.]+)rem$/从text-2.5rem中捕获2.5 - 传入
e函数处理任意输入:matchUtilities({ 'text-fluid': (value) => ({ fontSize: e(value) }) }, { values: { sm: '0.875rem', lg: '1.125rem' }, supportsVariants: true }) -
supportsVariants: true是关键,否则sm:text-fluid-sm这类写法不会生成对应规则
content 数组漏掉路径,配置再对也白搭
这是最常被忽略的一环:插件加完后,如果 content 数组没覆盖所有使用该自定义类的文件路径,这些类根本不会出现在最终 CSS 里。
- 比如你在
src/components/MyButton.vue里用了text-fluid-sm,但content只写了["./src/App.vue"],那这个类就永远不会生成 - 务必确保
content包含所有实际使用位置,常见写法:["./src/**/*.{vue,js,ts,jsx,tsx}", "./public/index.html"] - 2026 年 7 月起,Tailwind CLI 对
content扫描更严格,路径遗漏导致“类存在但不生效”的问题明显增多


















