Skip to content

内容配置

配置项目的内容来源。

您的 tailwind.config.js 文件中的 content 部分是您配置所有 HTML 模板、JavaScript 组件以及包含 Tailwind 类名的任何其他源文件的路径的地方。

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  // ...
}

这个指南涵盖了你需要了解的一切,以确保 Tailwind 为你的项目生成所需的所有 CSS。

配置源路径

Tailwind CSS 通过扫描你的所有 HTML、JavaScript 组件和任何其他模板文件中的类名,然后为这些样式生成所有相应的 CSS。

为了让Tailwind生成你所需的所有CSS,它需要知道项目中包含任何Tailwind类名的每个文件。

在配置文件的 content 部分配置所有内容文件的路径:

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}'
  ],
  // ...
}

路径配置为通配符模式,可以轻松匹配项目中的所有内容文件,无需大量配置:

  • 使用 * 来匹配除斜杠和隐藏文件之外的任何内容
  • 使用 ** 来匹配零个或多个目录
  • {} 之间使用逗号分隔的值来匹配选项列表

Tailwind 在底层使用 fast-glob 库,查看它们的文档以了解其他支持的模式特性。

路径是相对于您的项目根目录而不是您的 tailwind.config.js 文件,因此,如果您的 tailwind.config.js 文件位于自定义位置,您仍应该相对于项目根目录编写您的路径。

模式建议

为了获得最佳性能并避免误报,尽可能具体地配置您的内容。

如果您使用这样一个非常宽泛的模式,Tailwind 甚至会扫描 node_modules 中的内容,这可能不是您想要的。

✘ 不要使用非常宽泛的模式。

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './**/*.{html,js}',
  ],
  // ...
}

如果您有任何需要扫描的位于项目根目录的文件(通常是一个 index.html 文件),请单独列出该文件,以便您的其他模式可以更具体:

✓ 以具体的内容模式为准

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './components/**/*.{html,js}',
    './pages/**/*.{html,js}',
    './index.html',
  ],
  // ...
}

一些框架将它们的主 HTML 入口点隐藏在与其余模板不同的位置(通常是 public/index.html ),因此,如果您要向该文件添加 Tailwind 类,请确保它也包含在您的配置中:

✓ 如适用,请记得包括您的 HTML 入口点

js
module.exports = {
  content: [
    './public/index.html',
    './src/**/*.{html,js}',
  ],
  // ...
}

如果您有任何操作 HTML 以添加类的 JavaScript 文件,请确保也包括这些文件:

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    // ...
    './src/**/*.js',
  ],
  // ...
}
js
// ...
menuButton.addEventListener('click', function () {
  let classList = document.getElementById('nav').classList
  classList.toggle('hidden')
  classList.toggle('block')
})
// ...

重要的是不要扫描任何 CSS 文件 — 配置 Tailwind 以扫描模板,其中使用了类名,而不是 Tailwind 生成的 CSS 文件。

✓ 永远不要在内容配置中包含 CSS 文件

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './src/**/*.css',
  ],
  // ...
}

深入了解类检测

Tailwind 扫描源代码中的类的方式故意非常简单 —— 我们实际上不解析或执行代码所写的语言,只是使用正则表达式提取可能是类名的每个字符串。

例如,这是一些 HTML,其中每个潜在的类名字符串都被单独突出显示:

html
<div class="md:flex">
  <div class="md:flex-shrink-0">
    <img class="rounded-lg md:w-56" src="/img/shopping.jpg" alt="Woman paying for a purchase">
  </div>
  <div class="mt-4 md:mt-0 md:ml-6">
    <div class="uppercase tracking-wide text-sm text-indigo-600 font-bold">
      Marketing
    </div>
    <a href="/get-started" class="block mt-1 text-lg leading-tight font-semibold text-gray-900 hover:underline">
      Finding customers for your new business
    </a>
    <p class="mt-2 text-gray-600">
      Getting a new business off the ground is a lot of hard work.
      Here are five ideas you can use to find your first customers.
    </p>
  </div>
</div>

我们不仅仅限制搜索 class="..." 属性,因为您可能在任何地方使用类,比如在一些用于切换菜单的 JavaScript 中:

html
<script>
  menuButton.addEventListener('click', function () {
    let classList = document.getElementById('nav').classList
    classList.toggle('hidden')
    classList.toggle('block')
  })
</script>

通过使用这种非常简单的方法,Tailwind 与任何编程语言(例如 JSX)非常可靠地工作:

jsx
const sizes = {
  md: 'px-4 py-2 rounded-md text-base',
  lg: 'px-5 py-3 rounded-lg text-lg',
}

const colors = {
  indigo: 'bg-indigo-500 hover:bg-indigo-600 text-white',
  cyan: 'bg-cyan-600 hover:bg-cyan-700 text-white',
}

export default function Button({ color, size, children }) {
  let colorClasses = colors[color]
  let sizeClasses = sizes[size]

  return (
    <button type="button" className={`font-bold ${sizeClasses} ${colorClasses}`}>
      {children}
    </button>
  )
}

动态类名

Tailwind 提取类名的最重要含义是,它只会在源文件中找到完整的、不间断的字符串形式存在的类。

如果你使用字符串插值或将部分类名连接在一起,Tailwind 将无法找到它们,因此也不会生成相应的 CSS:

✘ 不要动态构造类名

html
<div class="text-{{ error ? 'red' : 'green' }}-600"></div>

在上面的示例中,字符串 text-red-600text-green-600 不存在,因此 Tailwind 不会生成这些类。

相反,请确保您正在使用的任何类名都完整存在:

✓ 始终使用完整的类名

html
<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>

如果您正在使用像 React 或 Vue 这样的组件库,这意味着您不应该使用 props 来动态构建类:

✘ 不要使用 props 来动态构建类名

jsx
function Button({ color, children }) {
  return (
    <button className={`bg-${color}-600 hover:bg-${color}-500 ...`}>
      {children}
    </button>
  )
}

相反,将 props 映射到在构建时静态可检测的完整类名:

✓ 始终将 props 映射到静态类名

jsx
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>
  )
}

这样做的另一个好处是让您能够将不同的属性值映射到不同的颜色深浅,例如:

jsx
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>
  )
}

只要您在代码中始终使用完整的类名,Tailwind 每次都会完美地生成所有的 CSS。

与第三方库一起使用

如果您正在使用任何第三方库(例如 Select2)并使用自定义 CSS 对该库进行样式设置,我们建议在不使用 Tailwind 的 @layer 功能的情况下编写这些样式。

css
@tailwind base;
@tailwind components;

.select2-dropdown {
  @apply rounded-b-lg shadow-md;
}
.select2-search {
  @apply border border-gray-300 rounded;
}
.select2-results__group {
  @apply text-lg font-bold text-gray-900;
}
/* ... */

@tailwind utilities;

这将确保 Tailwind 始终在您的 CSS 中包含这些样式,这比配置 Tailwind 扫描第三方库的源代码要容易得多。

如果您已经创建了自己的可重用的组件集,并使用 Tailwind 进行样式设置,并在多个项目中导入它们,请确保配置 Tailwind 以扫描这些组件的类名:

js
module.exports = {
  content: [
    './components/**/*.{html,js}',
    './pages/**/*.{html,js}',
    './node_modules/@my-company/tailwind-components/**/*.js',	
  ],
  // ...
}

这将确保 Tailwind 生成所有这些组件所需的 CSS。

如果您在具有工作区的 monorepo 中工作,您可能需要使用 require.resolve 来确保 Tailwind 能够看到您的内容文件:

js
const path = require('path');

module.exports = {
  content: [
    './components/**/*.{html,js}',
    './pages/**/*.{html,js}',
    path.join(path.dirname(require.resolve('@my-company/tailwind-components')), '**/*.js'),	
  ],
  // ...
}

使用相对路径

默认情况下,Tailwind 解析非绝对内容路径相对于当前工作目录,而不是 tailwind.config.js 文件。如果您从不同的目录运行 Tailwind,这可能会导致意外的结果。

要始终相对于 tailwind.config.js 文件解析路径,请使用对象表示法进行 content 配置,并将 relative 属性设置为 true

js
module.exports = {
  content: {
    relative: true,		
    files: [
      './pages/**/*.{html,js}',
      './components/**/*.{html,js}',
    ],
  },
  // ...
}

这很可能会成为框架下一个主要版本的默认行为。

配置原始内容

如果出于任何原因,您需要配置 Tailwind 以扫描一些原始内容而不是文件的内容,请使用一个带有 raw 键的对象,而不是路径:

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
    { raw: '<div class="font-bold">', extension: 'html' },
  ],
  // ...
}

对于这种情况,通常没有太多有效的用例 — 安全白名单通常才是你真正想要的。

安全白名单类

为了获得最小的文件大小和最佳的开发体验,我们强烈建议尽可能依赖您的 content 配置,告诉 Tailwind 尽可能多地生成哪些类。

白名单是最后的手段,只应在无法扫描某些内容的类名的情况下使用。这种情况很少见,你几乎永远不需要这个功能。

如果您需要确保 Tailwind 生成某些在您的内容文件中不存在的类名,请使用 safelist 选项:

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  safelist: [
    'bg-red-500',
    'text-3xl',
    'lg:text-4xl',
  ]
  // ...
}

这种情况可以派上用场的一个例子是,如果您的网站显示用户生成的内容,并且您希望用户能够在其内容中使用一组受限的 Tailwind 类,而这些类可能在您自己网站的源文件中不存在。

使用正则表达式

Tailwind 支持基于模式的安全列表,用于需要安全列出大量类的情况:

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  safelist: [
    'text-2xl',
    'text-3xl',
    {
      pattern: /bg-(red|green|blue)-(100|200|300)/,
    },
  ],
  // ...
}

模式只能匹配基本实用程序名称,如 /bg-red-.+/ ,如果模式包括变体修饰符,将不会匹配 /hover:bg-red-.+/

如果您想强制 Tailwind 为任何匹配的类生成变体,请使用 variants 选项包含它们:

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  safelist: [
    'text-2xl',
    'text-3xl',
    {
      pattern: /bg-(red|green|blue)-(100|200|300)/,
      variants: ['lg', 'hover', 'focus', 'lg:hover'],
    },
  ],
  // ...
}

丢弃类

由于 Tailwind 在检测内容中的类名时采用了非常简单的方法,您可能会发现一些您实际上并不需要的类被生成了。

例如,即使没有实际使用 container 类,以下 HTML 仍会生成该类:

html
<div class="text-lg leading-8 text-gray-600">
  Every custom pool we design starts as a used shipping container, and is
  retrofitted with state of the art technology and finishes to turn it into
  a beautiful and functional way to entertain your guests all summer long.
</div>

您可能还希望在某些情况下阻止 Tailwind 生成某些类,当这些类与现有的 CSS 冲突时,但您不希望给所有 Tailwind 类都加前缀。

在这些情况下,您可以使用 blocklist 选项来告诉 Tailwind 忽略在您的内容中检测到的特定类。

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
  ],
  blocklist: [
    'container',
    'collapse',
  ],
  // ...
}

选项 blocklist 只影响由 Tailwind 生成的 CSS,而不影响您自己编写的自定义 CSS 或从其他库导入的 CSS。

safelist 不同,选项 blocklist 仅支持字符串,并且您不能使用正则表达式阻止类。

转换源文件

如果您正在以编译为 HTML 的格式(如 Markdown)撰写内容,通常在扫描类名之前将内容编译为 HTML 是有意义的。

使用 content.transform 选项来转换匹配特定文件扩展名的任何内容,然后提取类名:

js
const remark = require('remark')

module.exports = {
  content: {
    files: ['./src/**/*.{html,md}'],
    transform: {
      md: (content) => {
        return remark().process(content)
      }
    }
  },
  // ...
}

在使用 content.transform 时,您需要使用 content.files 来提供源路径,而不是作为 content 下的顶级数组。

自定义提取逻辑

使用 extract 选项来覆盖 Tailwind 用于检测特定文件扩展名的类名逻辑:

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: {
    files: ['./src/**/*.{html,wtf}'],
    extract: {
      wtf: (content) => {
        return content.match(/[^<>"'`\s]*/g)
      }
    }
  },
  // ...
}

这是一个高级功能,大多数用户不需要它 - Tailwind 中的默认提取逻辑几乎适用于所有项目。

与转换一样,在使用 content.extract 时,您需要使用 content.files 而不是作为 content 下的顶级数组提供您的源路径。

故障排除

类没有生成

如果Tailwind没有生成类,请确保您的 content 配置正确,并匹配所有正确的源文件。

一个常见的错误是缺少文件扩展名,例如,如果您在 React 组件中使用 jsx 而不是 js

js
module.exports = {
  content: [
    './src/**/*.{html,js}',		
    './src/**/*.{html,js,jsx}'
  ],
  // ...
}

或者在项目进行中创建一个原本没有涵盖的新文件夹,然后忘记将其添加到配置中:

js
module.exports = {
  content: [
    './pages/**/*.{html,js}',
    './components/**/*.{html,js}',
    './util/**/*.{html,js}'
  ],
  // ...
}

也可能是您试图使用动态类名,这是行不通的,因为 Tailwind 实际上不会评估您的源代码,只能检测静态的不间断的类字符串。

✘ 不要动态构造类名

html
<div class="text-{{ error ? 'red' : 'green' }}-600"></div>

确保您在代码中始终使用完整的类名:

✓ 始终使用完整的类名

html
<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>

阅读我们关于动态类名的文档以获取更多详细信息。

样式在无限循环中重建

如果您的 CSS 似乎在无限循环中重建,很有可能是因为您的构建工具在注册 PostCSS 依赖项时不支持 glob 选项。

许多构建工具(如 webpack)不支持此选项,因此我们只能告诉它们监视特定文件或整个目录。例如,我们无法告诉 webpack 仅监视目录中的 *.html 文件。

这意味着如果构建您的 CSS 导致这些目录中的任何文件发生更改,将触发重新构建,即使更改的文件与您的 glob 中的扩展名不匹配。

js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    // With some build tools, your CSS will rebuild
    // any time *any* file in `src` changes.
    './src/**/*.{html,js}',
  ],
  // ...
}

所以如果你正在观察 src/**/*.html 进行更改,但你正在将你的CSS输出文件写入 src/css/styles.css ,那么使用一些工具将会导致无限重建循环。

理想情况下,我们可以在控制台中警告您,但许多工具都可以完美支持它(包括我们自己的 CLI 工具),而我们没有可靠的方法来检测您正在使用的构建工具。

要解决这个问题,在您的 content 配置中使用更具体的路径,确保只包括在 CSS 构建时不会更改的目录。

js
module.exports = {
  content: [
    './src/**/*.{html,js}',				
    './src/pages/**/*.{html,js}',		
    './src/components/**/*.{html,js}',	
    './src/layouts/**/*.{html,js}',		
    './src/index.html',					
  ],
  // ...
}

如果需要,调整实际项目目录结构,以确保您可以定位模板文件,而不会意外捕捉到您的 CSS 文件或其他构建工件,如清单文件。

如果您绝对不能更改您的内容配置或目录结构,最好的选择是使用具有完整 glob 支持的工具单独编译您的 CSS。我们建议使用 Tailwind CLI,这是一个快速、简单、专门用于使用 Tailwind 编译 CSS 的工具。

它就是无法正常工作

如果您遇到输出方面的奇怪、难以描述的问题,或者似乎根本没有工作,很可能是因为您的构建工具不正确地(或根本不)支持 PostCSS 依赖消息。目前已知的一个例子是 Stencil

当您遇到这些问题时,我们建议使用 Tailwind CLI 将您的 CSS 单独编译,而不是尝试将 Tailwind 集成到您现有的工具中。

您可以使用像 npm-run-allconcurrently 这样的包,通过向项目添加一些脚本,将您的 CSS 与您通常的开发命令一起编译,就像这样:

json
{
  // ...
  "scripts": {
    "start": "concurrently \"npm run start:css\" \"react-scripts start\"",
    "start:css": "tailwindcss -o src/tailwind.css --watch",
    "build": "npm run build:css && react-scripts build",
    "build:css": "NODE_ENV=production tailwindcss -o src/tailwind.css -m",
  },
}

无论哪种方式,请务必检查现有问题提出新问题,以便我们可以找出问题并尝试改进与您正在使用的任何工具的兼容性。

Released under the MIT License.