addUtilities是唯一安全注入自定义工具类的API;它支持响应式、深色模式及hover等变体,而手写CSS会被按需生成机制忽略,且必须用tailwindcss/plugin包裹、配合正确content路径与theme.extend声明。

addUtilities 是唯一安全的注入方式
直接在 CSS 文件里写 .my-utility { color: red } 不会生效,Tailwind 的按需生成机制只扫描 content 路径中实际出现的类名字符串。手写 CSS 既绕过响应式前缀支持,也不触发深色模式、hover 等变体生成。
必须用插件系统 + addUtilities:它能确保类被纳入 Tailwind 的处理流程,支持 md:text-red-500、dark:bg-brand 等所有标准能力。
- 插件必须用
tailwindcss/plugin包裹,否则构建会静默跳过或报错theme is not a function -
addUtilities只接受扁平对象,不能写嵌套结构(如&:hover),这类需求该用addComponents - 类名含冒号(如
md:my-class)要双反斜杠转义,媒体查询键也得手动展开:'@media (min-width: 768px)'
自定义类如何支持 dark 模式和响应式
这些能力不会自动继承,必须显式组合选择器或媒体查询键。比如你要一个深色模式下生效的背景色类,不能只写 .bg-brand-dark,而得这样声明:
addUtilities({
'.dark .dark\:bg-brand': {
backgroundColor: theme('colors.brand.500')
}
})
响应式同理:想让 md:shadow-lg 生效,就得手动写出带 @media 的键:
立即学习“前端免费学习笔记(深入)”;
"@media (min-width: 768px)": {
".md\:shadow-lg": {
boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1)"
}
}
-
theme()只能读取theme.extend中已声明的路径,比如没在extend.colors.brand里定义,theme('colors.brand.500')就返回undefined - 所有自定义类名(包括带前缀的)都必须出现在
content数组覆盖的文件路径里,否则根本不会生成 CSS
动态类名(如 text-2.5rem)必须用 matchUtilities
硬编码 text-xs、text-sm、text-lg 还行,但遇到 text-2.5rem 或 aspect-16/9 就得换方案——matchUtilities 是专为这类正则匹配场景设计的 API。
它能提取类名中的值并传入回调函数处理,例如:
matchUtilities({
'text-fluid': (value) => ({
fontSize: value
})
}, {
values: {
sm: '0.875rem',
lg: '1.125rem'
},
supportsVariants: true
})
-
supportsVariants: true才能让md:text-fluid-sm这类写法生效 - 类名含斜杠(如
aspect-16/9)必须调用e('16/9')解构,否则生成的选择器非法 - 别试图用
addUtilities硬列所有aspect-1/1到aspect-21/9,维护成本高且易漏
插件注册和 content 配置最容易被忽略
插件写对了、addUtilities 也用了,但类还是不出现?八成是这两个地方漏了:
-
plugins数组里没require('./plugins/my-utility.js')—— Tailwind 不会自动加载本地插件文件 -
content没覆盖到使用该类的模板文件,比如你在Svelte组件里写了class="text-gradient",但content只写了["./src/**/*.js"],那这个类压根不会进最终 CSS - 路径错误(如少写
.js后缀)、模块语法不匹配(import但没设"type": "module")也会导致构建失败或静默失效
真正容易被忽略的是:插件加完后,content 必须覆盖所有使用该类的文件路径——哪怕配置全对,漏了 ./src,类就等于不存在。



















