在源文件中检测 class
理解并自定义 Tailwind 如何扫描源文件。
概述
Tailwind 的工作方式是扫描项目中的 utility class,然后根据你实际用到的 class 生成所需 CSS。
这样可以让 CSS 尽可能小,同时也让任意值 这类功能成为可能。
class 如何被检测
Tailwind 会把所有源文件当作纯文本处理,不会尝试以任何方式把文件当成代码去解析。
它只会根据 class 名中可能出现的字符,在文件里查找可能是 class 的 token:
// [!code word:bg-blue-500]
// [!code word:rounded-full]
// [!code word:text-white]
// [!code word:text-black]
// [!code word:font-medium]
// [!code word:text-sm\/6]
// [!code word:font-sans]
// [!code word:bg-black]
// [!code word:bg-white]
// [!code word:className]
// [!code word:function]
// [!code word:children]
// [!code word:button]
// [!code word:shadow]
// [!code word:export]
// [!code word:colors]
// [!code word:color]
// [!code word:black]
// [!code word:white]
// [!code word:const]
// [!code word:blue]
// [!code word:return]
// [!code word:py-1.5]
// [!code word:px-2]
export function Button({ color, children }) {
const colors = {
black: "bg-black text-white",
blue: "bg-blue-500 text-white",
white: "bg-white text-black",
};
return (
<button className={`${colors[color]} rounded-full px-2 py-1.5 font-sans text-sm/6 font-medium shadow`}>
{children}
</button>
);
}然后它会尝试为这些 token 生成 CSS,并丢弃无法映射到框架已知 utility class 的 token。
动态 class 名
由于 Tailwind 把源文件当纯文本扫描,它无法理解你所用编程语言中的字符串拼接或插值。
DANGER
不要动态拼接 class 名
<div class="text-{{ error ? 'red' : 'green' }}-600"></div>上面的例子中并不存在 text-red-600 和 text-green-600 这两个字符串,因此 Tailwind 不会生成这些 class。
相反,请确保你使用的 class 名都是完整出现的:
TIP
始终使用完整的 class 名
<!-- [!code word:text-red-600] -->
<!-- [!code word:text-green-600] -->
<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>如果使用 React 或 Vue 这类组件库,这意味着你不应该用 props 动态拼接 class:
DANGER
不要用 props 动态构建 class 名
function Button({ color, children }) {
return <button className={`bg-${color}-600 hover:bg-${color}-500 ...`}>{children}</button>;
}相反,把 props 映射到在构建时就能静态检测到的完整 class 名:
TIP
始终把 props 映射到静态 class 名
function Button({ color, children }) {
const colorVariants = {
blue: "bg-blue-600 hover:bg-blue-500",
red: "bg-red-600 hover:bg-red-500",
};
return <button className={`${colorVariants[color]} ...`}>{children}</button>;
}这样做还有额外好处,例如可以把不同的 prop 值映射到不同的颜色色阶:
function Button({ color, children }) {
const colorVariants = {
blue: "bg-blue-600 hover:bg-blue-500 text-white",
red: "bg-red-500 hover:bg-red-400 text-white",
yellow: "bg-yellow-300 hover:bg-yellow-400 text-black",
};
return <button className={`${colorVariants[color]} ...`}>{children}</button>;
}只要代码里始终使用完整的 class 名,Tailwind 每次都能正确生成全部 CSS。
会扫描哪些文件
Tailwind 会扫描项目中的每个文件以查找 class 名,但以下情况除外:
- 位于
.gitignore中的文件 node_modules目录中的文件- 图片、视频、zip 等二进制文件
- CSS 文件
- 常见包管理器的 lock 文件
如果需要扫描 Tailwind 默认忽略的文件,可以显式注册 这些源。
显式注册源
使用 @source 显式注册相对于样式表的源路径:
@import "tailwindcss";
@source "../node_modules/@acmecorp/ui-lib";这在需要扫描用 Tailwind 构建的外部库时特别有用,因为依赖通常写在 .gitignore 里,默认会被 Tailwind 忽略。
设置基础路径
默认情况下,Tailwind 以当前工作目录为起点扫描 class 名。
若要显式设置源检测的基础路径,在 CSS 中导入 Tailwind 时使用 source() 函数:
/* [!code word:source("../src")] */
@import "tailwindcss" source("../src");在 monorepo 中,构建命令往往从仓库根目录而不是各个项目根目录运行,这时这个选项会很有用。
忽略特定路径
使用 @source not 在扫描 class 名时忽略相对于样式表的特定路径:
@import "tailwindcss";
@source not "../src/components/legacy";如果项目中有很大的目录确定不会使用 Tailwind class(例如遗留组件或第三方库),这个功能会很有用。
禁用自动检测
如果你想显式注册全部源,可以使用 source(none) 彻底禁用自动源检测:
/* [!code word:source("../src")] */
@import "tailwindcss" source(none);
@source "../admin";
@source "../shared";在包含多份 Tailwind 样式表的项目中,这可以确保每份样式表只包含各自需要的 class。
将特定 utility 加入 safelist
如果需要确保 Tailwind 生成内容文件中并不存在的某些 class 名,使用 @source inline() 强制生成它们:
@import "tailwindcss";
@source inline("underline");.underline {
text-decoration-line: underline;
}将变体加入 safelist
也可以用 @source inline() 生成带变体的 class。例如,要生成带 hover 和 focus 变体的 underline class,在源输入中加上 {hover:,focus:,}:
@import "tailwindcss";
@source inline("{hover:,focus:,}underline");.underline {
text-decoration-line: underline;
}
@media (hover: hover) {
.hover\:underline:hover {
text-decoration-line: underline;
}
}
@media (focus: focus) {
.focus\:underline:focus {
text-decoration-line: underline;
}
}使用范围加入 safelist
源输入会做花括号展开,因此可以一次生成多个 class。例如,要生成所有带 hover 变体的红色背景色,可以使用范围:
@import "tailwindcss";
@source inline("{hover:,}bg-red-{50,{100..900..100},950}");.bg-red-50 {
background-color: var(--color-red-50);
}
.bg-red-100 {
background-color: var(--color-red-100);
}
.bg-red-200 {
background-color: var(--color-red-200);
}
/* ... */
.bg-red-800 {
background-color: var(--color-red-800);
}
.bg-red-900 {
background-color: var(--color-red-900);
}
.bg-red-950 {
background-color: var(--color-red-950);
}
@media (hover: hover) {
.hover\:bg-red-50:hover {
background-color: var(--color-red-50);
}
/* ... */
.hover\:bg-red-950:hover {
background-color: var(--color-red-950);
}
}这会生成从 100 到 900、步长为 100 的红色背景色,再加上最浅的 50 和最深的 950。同时会为这些 class 各自加上 hover: 变体。
显式排除 class
使用 @source not inline() 可以阻止生成特定 class,即使它们出现在源文件中:
@import "tailwindcss";
@source not inline("{hover:,focus:,}bg-red-{50,{100..900..100},950}");这会显式排除红色背景 utility 及其 hover、focus 变体,不让它们被生成。