Skip to content

添加自定义样式

将您自己的自定义样式添加到 Tailwind 的最佳实践。

通常在使用框架时最大的挑战是弄清楚当框架无法为您处理某些需要时,您应该做什么。

Tailwind 从头开始设计为可扩展和可定制,因此无论您构建什么,您都不会感觉在与框架对抗。

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

定制您的主题

如果您想要更改颜色调色板、间距比例、排版比例或断点等内容,请将您的自定义内容添加到您的 theme 文件的 tailwind.config.js 部分中:

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 的方括号表示法,即可随意生成一个类。

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

这基本上就像内联样式,其主要好处是可以与交互式修饰符(如 hover )和响应式修饰符(如 lg )相结合:

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

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

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

甚至可以在您的 tailwind.config.js 文件中使用 theme 函数引用设计令牌

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

当使用 CSS 变量作为任意值时,不需要将变量包装在 var(...) 中 - 只提供实际的变量名称就足够了:

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

任意属性

如果您需要使用 Tailwind 没有默认包含的 CSS 属性,您也可以使用方括号表示法来编写完全任意的 CSS:

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

这真的很像内联样式,但再次受益于您可以使用修饰符:

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

这对于诸如 CSS 变量之类的东西可能很有用,特别是当它们需要在不同条件下进行更改时:

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

任意变体

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

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

Learn more in the arbitrary variants documentation. 在任意变体文档中了解更多信息。

处理空格

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

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

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

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

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

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

如果您正在使用类似 JSX 的东西,其中反斜杠被从呈现的 HTML 中剥离,请使用 String.raw(),以便反斜杠不被视为 JavaScript 转义字符:

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

解决歧义

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

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

html
<!-- 将生成字体大小实用程序 -->
<div class="text-[22px]">...</div>

<!-- 将生成字体颜色实用程序 -->
<div class="text-[#bada55]">...</div>

但有时确实是模棱两可的,例如在使用 CSS 变量时:

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

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

html
<!-- 将生成字体大小实用程序 -->
<div class="text-[length:var(--my-var)]">...</div>

<!-- 将生成字体颜色实用程序 -->
<div class="text-[color:var(--my-var)]">...</div>

使用 CSS 和 @layer

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

css
@tailwind base;
@tailwind components;
@tailwind utilities;

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

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

css
@tailwind base;
@tailwind components;
@tailwind utilities;

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

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

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

.bg-black {
  background: black;
}

在这里,由于 .bg-black 在CSS中出现在 .btn 之后,所以两个按钮都将是黑色的。

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

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

  • base 层用于重置规则或应用于普通HTML元素的默认样式等。
  • components 层用于基于类的样式,您希望能够使用实用程序来覆盖。
  • utilities 层用于小型、单一用途的类,始终应优先于任何其他样式。

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

通过 @layer 指令,您可以通过自动将样式重定位到相应的 @tailwind 指令来控制声明顺序,并为您自定义的 CSS 启用修饰符和摇树功能等功能。

添加基本样式

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

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

这样可以将基本样式决策与其他所有样式一起放在标记中,而不是将它们隐藏在单独的文件中。

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

css
@tailwind base;
@tailwind components;
@tailwind utilities;

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

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

添加组件类

使用 components 层用于您想要添加到项目中的更复杂的类,但仍希望能够使用实用类进行覆盖。

传统上,这些类可能是 cardbtnbadge 之类的东西。

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 层中定义组件类,您仍然可以在必要时使用实用类来覆盖它们:

html
<!-- 看起来像卡片,但四角是方形的 -->
<div class="card rounded-none">
	<!-- ... -->
</div>

使用 Tailwind 时,你可能不需要这些类型的类,就像你想象的那样频繁。阅读我们的重用样式指南获取我们的建议。

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

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 层:

css
@tailwind base;
@tailwind components;
@tailwind utilities;

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

当您的项目中有一些 CSS 功能,Tailwind 没有默认提供工具类时,这将会非常有用。

使用自定义 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>

Learn more about how these modifiers work in the Hover, Focus, and Other States documentation. 了解有关这些修饰符在悬停、焦点和其他状态文档中的工作方式。

移除未使用的自定义 CSS

只有在 HTML 中实际使用了您添加到 base 层、components 层或 utilities 层的自定义样式时,这些样式才会包含在编译好的 CSS 中。

css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
	/* 除非您实际使用,否则编译后的 CSS 中不会包含它 */
	.card {
		/* ... */
	}
}

如果要添加一些应始终包含的自定义 CSS,可将其添加到样式表中,而无需使用 @layer 指令:

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 插件:

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

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

层和每个组件的 CSS

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

尽管您可以在组件样式中像这样使用 @applytheme 等功能,但 @layer 指令将无法工作,您将看到有关 @layer 在没有匹配的 @tailwind 指令的错误:

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

vue
<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` 的情况下添加您的样式

vue
<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 的实用工具而不是组件样式

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

编写插件

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

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',
        }
      })
    })
  ]
}

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

Released under the MIT License.