使用框架时,通常最大的挑战在于弄清楚当框架无法处理你所需内容时你应该怎么做。

Tailwind 从一开始就设计为可扩展且可定制的,因此无论你构建什么,你都不会觉得你在与框架作斗争。

本指南涵盖了诸如自定义设计令牌、必要时如何突破这些约束、添加自定义 CSS 以及使用插件扩展框架等主题。

自定义主题

如果你想更改诸如颜色调色板、间距比例、字体比例或断点之类的内容,请将自定义内容添加到 tailwind.config.js 文件的 theme 部分

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  theme: {
    screens: {
      sm: '480px',
      md: '768px',
      lg: '976px',
      xl: '1440px',
    },
    colors: {
      'blue': '#1fb6ff',
      'pink': '#ff49db',
      'orange': '#ff7849',
      'green': '#13ce66',
      'gray-dark': '#273444',
      'gray': '#8492a6',
      'gray-light': '#d3dce6',
    },
    fontFamily: {
      sans: ['Graphik', 'sans-serif'],
      serif: ['Merriweather', 'serif'],
    },
    extend: {
      spacing: {
        '128': '32rem',
        '144': '36rem',
      },
      borderRadius: {
        '4xl': '2rem',
      }
    }
  }
}

主题配置 文档中了解有关自定义主题的更多信息。


使用任意值

虽然你通常可以使用一组受限的设计令牌构建精心设计的绝大部分内容,但偶尔你需要突破这些限制才能让事物达到像素完美。

当你发现自己真正需要像top: 117px这样的东西才能将背景图像放在正确的位置时,使用 Tailwind 的方括号表示法来生成一个类,其中包含任意值

<div class="top-[117px]">
  <!-- ... -->
</div>

这基本上就像内联样式,其主要优点是你可以将其与交互式修饰符(如hover)和响应式修饰符(如lg)结合使用

<div class="top-[117px] lg:top-[344px]">
  <!-- ... -->
</div>

这适用于框架中的所有内容,包括背景颜色、字体大小、伪元素内容等

<div class="bg-[#bada55] text-[22px] before:content-['Festivus']">
  <!-- ... -->
</div>

甚至可以使用theme函数来引用tailwind.config.js文件中的设计标记

<div class="grid grid-cols-[fit-content(theme(spacing.32))]">
  <!-- ... -->
</div>

在将 CSS 变量用作任意值时,不需要将变量包装在var(...)中——只需提供实际变量名称即可

<div class="bg-[--my-color]">
  <!-- ... -->
</div>

任意属性

如果你需要使用 Tailwind 开箱即用不包含实用程序的 CSS 属性,你还可以使用方括号表示法来编写完全任意的 CSS

<div class="[mask-type:luminance]">
  <!-- ... -->
</div>

非常像内联样式,但同样具有可以使用修饰符的优点

<div class="[mask-type:luminance] hover:[mask-type:alpha]">
  <!-- ... -->
</div>

这对于 CSS 变量等内容也很有用,尤其是在它们需要在不同条件下更改时

<div class="[--scroll-offset:56px] lg:[--scroll-offset:44px]">
  <!-- ... -->
</div>

任意变体

任意变体就像任意值,但用于进行即时选择器修改,就像你可以使用内置伪类变体(如hover:{utility})或响应式变体(如md:{utility})一样,但直接在 HTML 中使用方括号表示法。

<ul role="list">
  {#each items as item}
    <li class="lg:[&:nth-child(3)]:hover:underline">{item}</li>
  {/each}
</ul>

任意变体文档中了解更多信息。

处理空格

当任意值需要包含空格时,请改用下划线(_),Tailwind 将在构建时自动将其转换为空格

<div class="grid grid-cols-[1fr_500px_2fr]">
  <!-- ... -->
</div>

在使用下划线很常见但空格无效的情况下,Tailwind 将保留下划线,而不是将其转换为空格,例如在 URL 中

<div class="bg-[url('/what_a_rush.png')]">
  <!-- ... -->
</div>

在极少数情况下,您实际上需要使用下划线,但由于空格也是有效的,因此存在歧义,请使用反斜杠转义下划线,Tailwind 不会将其转换为空格

<div class="before:content-['hello\_world']">
  <!-- ... -->
</div>

如果您使用的是 JSX 等内容,其中反斜杠从呈现的 HTML 中被删除,请使用 String.raw(),这样反斜杠就不会被视为 JavaScript 转义字符

<div className={String.raw`before:content-['hello\_world']`}>
  <!-- ... -->
</div>

解决歧义

Tailwind 中的许多实用程序共享一个公共命名空间,但映射到不同的 CSS 属性。例如,text-lgtext-black 都共享 text- 命名空间,但一个用于 font-size,另一个用于 color

在使用任意值时,Tailwind 通常可以根据您传入的值自动处理此歧义

<!-- Will generate a font-size utility -->
<div class="text-[22px]">...</div>

<!-- Will generate a color utility -->
<div class="text-[#bada55]">...</div>

不过,有时确实存在歧义,例如在使用 CSS 变量时

<div class="text-[var(--my-var)]">...</div>

在这些情况下,您可以通过在值之前添加 CSS 数据类型 来向 Tailwind “提示” 基础类型

<!-- Will generate a font-size utility -->
<div class="text-[length:var(--my-var)]">...</div>

<!-- Will generate a color utility -->
<div class="text-[color:var(--my-var)]">...</div>

使用 CSS 和 @layer

当您需要向 Tailwind 项目添加真正自定义的 CSS 规则时,最简单的方法就是将自定义 CSS 添加到您的样式表中

main.css
@tailwind base;
@tailwind components;
@tailwind utilities;

.my-custom-style {
  /* ... */
}

为了获得更多功能,你还可以使用 @layer 指令向 Tailwind 的 basecomponentsutilities 层添加样式

main.css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .my-custom-style {
    /* ... */
  }
}
为什么 Tailwind 将样式分组到“层”中?

在 CSS 中,样式表中规则的顺序决定了当两个选择器具有相同特异性时哪个声明获胜

.btn {
  background: blue;
  /* ... */
}

.bg-black {
  background: black;
}

这里,两个按钮都将为黑色,因为 .bg-black 在 CSS 中位于 .btn 之后

<button class="btn bg-black">...</button>
<button class="bg-black btn">...</button>

为了管理这一点,Tailwind 将其生成的样式组织成三个不同的“层”——一个由 ITCSS 推广的概念。

  • base 层用于诸如重置规则或应用于普通 HTML 元素的默认样式之类的内容。
  • components 层用于基于类的样式,你希望能够使用实用程序覆盖这些样式。
  • utilities 层用于小而单一用途的类,它们始终应优先于任何其他样式。

明确这一点使理解你的样式将如何相互作用变得更容易,并且使用 @layer 指令让你能够控制最终的声明顺序,同时仍可以按照你喜欢的方式组织你的实际代码。

@layer 指令通过自动将你的样式重新定位到相应的 @tailwind 指令来帮助你控制声明顺序,并且还为你的自定义 CSS 启用诸如 修饰符tree-shaking 等功能。

添加基础样式

如果你只想为页面设置一些默认值(比如文本颜色、背景颜色或字体系列),最简单的选择就是向 htmlbody 元素添加一些类

<!doctype html>
<html lang="en" class="text-gray-900 bg-gray-100 font-serif">
  <!-- ... -->
</html>

这会将你的基本样式决策保留在标记中,与所有其他样式并列,而不是将它们隐藏在单独的文件中。

如果你想为特定的 HTML 元素添加自己的默认基本样式,请使用 @layer 指令将这些样式添加到 Tailwind 的 base

main.css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  h1 {
    @apply text-2xl;
  }
  h2 {
    @apply text-xl;
  }
  /* ... */
}

如果你想引用 主题 中定义的任何值,请在添加自定义基本样式时使用 theme 函数或 @apply 指令。

添加组件类

对于你希望添加到项目中的任何更复杂的类,请使用 components 层,你仍然希望能够用实用程序类覆盖它们。

传统上这些类类似于 cardbtnbadge — 类似这样的东西。

main.css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .card {
    background-color: theme('colors.white');
    border-radius: theme('borderRadius.lg');
    padding: theme('spacing.6');
    box-shadow: theme('boxShadow.xl');
  }
  /* ... */
}

通过在 components 层中定义组件类,你仍然可以在必要时使用实用程序类覆盖它们

<!-- Will look like a card, but with square corners -->
<div class="card rounded-none">
  <!-- ... -->
</div>

使用 Tailwind 时,你可能不需要像你认为的那么频繁地使用这些类型的类。阅读我们的 重复使用样式 指南,了解我们的建议。

components 层也是放置你正在使用的任何第三方组件的自定义样式的好地方

main.css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer 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;
  }
  /* ... */
}

如果你想引用 主题 中定义的任何值,请在添加自定义组件样式时使用 theme 函数或 @apply 指令。

添加自定义实用程序

将你自己的任何自定义实用程序类添加到 Tailwind 的utilities

main.css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer utilities {
  .content-auto {
    content-visibility: auto;
  }
}

当你的项目中需要使用 Tailwind 未开箱即用的 CSS 功能时,这会很有用。

使用自定义 CSS 的修饰符

使用@layer添加到 Tailwind 的任何自定义样式都将自动支持 Tailwind 的修饰符语法,用于处理诸如悬停状态、响应式断点、暗模式等内容。

CSS
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer utilities {
  .content-auto {
    content-visibility: auto;
  }
}
HTML
<div class="lg:dark:content-auto">
  <!-- ... -->
</div>

悬停、聚焦和其他状态文档中了解有关这些修饰符如何工作的更多信息。

删除未使用的自定义 CSS

添加到basecomponentsutilities层的任何自定义样式都只会包含在编译的 CSS 中,如果这些样式实际上在 HTML 中使用的话。

main.css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  /* This won't be included in your compiled CSS unless you actually use it */
  .card {
    /* ... */
  }
}

如果你想添加一些始终应该包含的自定义 CSS,请在不使用@layer指令的情况下将其添加到你的样式表中

main.css
@tailwind base;
@tailwind components;

/* This will always be included in your compiled CSS */
.card {
  /* ... */
}

@tailwind utilities;

确保将你的自定义样式放在需要的位置,以获得你想要的优先级行为。在上面的示例中,我们在@tailwind utilities之前添加了.card类,以确保实用程序仍然可以覆盖它。

使用多个 CSS 文件

如果您编写大量 CSS 并将其组织到多个文件中,请确保在使用 Tailwind 处理这些文件之前将这些文件合并到单个样式表中,否则您会看到有关使用 @layer 但没有相应的 @tailwind 指令的错误。

最简单的方法是使用 postcss-import 插件

postcss.config.js
module.exports = {
  plugins: {
    'postcss-import': {},
    tailwindcss: {},
    autoprefixer: {},
  }
}

在我们的 构建时导入 文档中了解更多信息。

图层和按组件 CSS

Vue 和 Svelte 等组件框架支持在每个组件文件中存在的 <style> 块中添加按组件样式。

虽然您可以像这样在组件样式中使用 @applytheme 等功能,但 @layer 指令将不起作用,您会看到有关使用 @layer 但没有匹配的 @tailwind 指令的错误

不要在组件样式中使用 @layer

Card.svelte
<div>
  <slot></slot>
</div>

<style>
  /* Won't work because this file is processed in isolation */
  @layer components {
    div {
      background-color: theme('colors.white');
      border-radius: theme('borderRadius.lg');
      padding: theme('spacing.6');
      box-shadow: theme('boxShadow.xl');
    }
  }
</style>

这是因为在底层,Vue 和 Svelte 等框架独立处理每个 <style> 块,并对每个块独立运行您的 PostCSS 插件链。

这意味着如果您有 10 个每个都有 <style> 块的组件,那么 Tailwind 将运行 10 次,并且每次运行都不知道其他运行。因此,Tailwind 无法获取您在 @layer 中定义的样式并将其移动到相应的 @tailwind 指令,因为就 Tailwind 所知,没有 @tailwind 指令可以将其移动到。

对此的一个解决方案是简单地在组件样式中使用 @layer

在不使用 @layer 的情况下添加您的样式

Card.svelte
<div>
  <slot></slot>
</div>

<style>
  div {
    background-color: theme('colors.white');
    border-radius: theme('borderRadius.lg');
    padding: theme('spacing.6');
    box-shadow: theme('boxShadow.xl');
  }
</style>

您将失去控制样式优先级的功能,但遗憾的是,由于这些工具的工作方式,这完全超出了我们的控制范围。

我们的建议是,您根本不要像这样使用组件样式,而是按照预期的方式使用 Tailwind——作为单个全局样式表,您可以在 HTML 中直接使用类

使用 Tailwind 的实用程序,而不是组件样式

Card.svelte
<div class="bg-white rounded-lg p-6 shadow-xl">
  <slot></slot>
</div>

编写插件

您还可以使用 Tailwind 的插件系统向您的项目添加自定义样式,而不是使用 CSS 文件

tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  // ...
  plugins: [
    plugin(function ({ addBase, addComponents, addUtilities, theme }) {
      addBase({
        'h1': {
          fontSize: theme('fontSize.2xl'),
        },
        'h2': {
          fontSize: theme('fontSize.xl'),
        },
      })
      addComponents({
        '.card': {
          backgroundColor: theme('colors.white'),
          borderRadius: theme('borderRadius.lg'),
          padding: theme('spacing.6'),
          boxShadow: theme('boxShadow.xl'),
        }
      })
      addUtilities({
        '.content-auto': {
          contentVisibility: 'auto',
        }
      })
    })
  ]
}

插件文档中了解有关编写您自己的插件的更多信息。