核心概念
向 Tailwind 添加您自己的自定义样式的最佳实践。
使用框架时最大的挑战通常是弄清楚当您需要某些框架无法为您处理的东西时您应该做什么。
Tailwind 从一开始就被设计为可扩展和可定制的,因此无论您构建什么,您都不会感觉自己正在与框架作斗争。
本指南涵盖了自定义设计令牌、如何在必要时摆脱这些限制、添加您自己的自定义 CSS 以及使用插件扩展框架等主题。
如果您想要更改调色板、间距比例、排版比例或断点等内容,请将您的自定义内容添加到tailwind.config.js
文件的theme
部分:
/** @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',
}
}
}
}
更多自定义主题请参考 Theme Configuration 文档。
虽然您通常可以使用一组受限的设计令牌来构建精心设计的大部分内容,但有时您需要突破这些限制才能获得完美像素。
当你发现自己确实需要像 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>
在arbitrary variants 文档中了解更多信息。
当任意值需要包含空格时,请使用下划线(_
),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-lg
和text-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 data type 来向 Tailwind “hint”底层类型:
<!-- 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>
当你需要向 Tailwind 项目添加真正的自定义 CSS 规则时,最简单的方法就是将自定义 CSS 添加到样式表中:
@tailwind base;
@tailwind components;
@tailwind utilities;
.my-custom-style {
/* ... */
}
为了获得更多功能,您还可以使用 @layer
指令将样式添加到 Tailwind 的 base
、components
和 utilities
层:
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.my-custom-style {
/* ... */
}
}
在 CSS 中,当两个选择器具有相同的特异性时,样式表中规则的顺序决定哪个声明获胜:
.btn {
background: blue;
/* ... */
}
.bg-black {
background: black;
}
在这里,两个按钮都是黑色的,因为 CSS 中 .bg-black
位于 .btn
之后:
<button class="btn bg-black">...</button>
<button class="bg-black btn">...</button>
为了管理这个问题,Tailwind 将其生成的样式组织成三个不同的“层”——这个概念由 [ITCSS](https://www.x Five.co/blog/itcss-scalable-maintainable-css-architecture/#what- is-itcss)。
base
层用于重置规则或应用于纯 HTML 元素的默认样式等内容。components
层用于您希望能够使用实用程序覆盖的基于类的样式。utilities
层适用于小型、单一用途的类,这些类应始终优先于任何其他样式。明确这一点可以更容易地理解您的样式如何相互交互,并且使用@layer
指令可以让您控制最终的声明顺序,同时仍然以您喜欢的任何方式组织实际代码。
@layer
指令通过自动将样式重新定位到相应的 @tailwind
指令来帮助您控制声明顺序,并且还启用诸如 modifiers 和 tree-shaking 之类的功能用于您自己的自定义 CSS。
如果您只想为页面设置一些默认值(例如文本颜色、背景颜色或字体系列),最简单的选择就是向html
或body
元素添加一些类:
<!doctype html>
<html lang="en" class="text-gray-900 bg-gray-100 font-serif">
<!-- ... -->
</html>
这会将您的基本样式决策与所有其他样式一起保存在您的标记中,而不是将它们隐藏在单独的文件中。
如果您想为特定 HTML 元素添加自己的默认基本样式,请使用 @layer
指令将这些样式添加到 Tailwind 的 base
层:
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
h1 {
@apply text-2xl;
}
h2 {
@apply text-xl;
}
/* ... */
}
如果您想要引用 theme
中定义的任何值,请在添加自定义基本样式时使用 theme
函数或 @apply
指令。
对于您想要添加到项目中的任何更复杂的类,请使用 components
层,并且您仍希望能够使用实用程序类覆盖这些类。
传统上,这些将是像 card
、btn
、badge
这样的类。
@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 后,您可能不需要像您想象的那样频繁地参加这些类型的课程。请阅读我们关于 Reusing Styles 的指南,了解我们的建议。
components
层也是放置您正在使用的任何第三方组件的自定义样式的好地方:
@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 中定义的任何值,请在添加自定义组件样式时使用 theme
函数或 @apply
指令。
将您自己的任何自定义实用程序类添加到 Tailwind 的 utilities
层:
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.content-auto {
content-visibility: auto;
}
}
当您想要在项目中使用某个 CSS 功能而 Tailwind 没有包含开箱即用的实用程序时,此功能非常有用。
您使用 @layer
添加到 Tailwind 的任何自定义样式都将自动支持 Tailwind 的修饰符语法,以处理悬停状态、响应断点、暗模式等。
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.content-auto {
content-visibility: auto;
}
}
<div class="lg:dark:content-auto">
<!-- ... -->
</div>
在 Hover, Focus, and Other States 文档中了解有关这些修饰符如何工作的更多信息。
您添加到 base
、components
或 utilities
层的任何自定义样式仅当您的 HTML 中实际使用时才会包含在您编译的 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
指令:
@tailwind base;
@tailwind components;
/* This will always be included in your compiled CSS */
.card {
/* ... */
}
@tailwind utilities;
确保将自定义样式放在需要的位置,以获得所需的优先行为。在上面的示例中,我们在 @tailwind utilities
之前添加了 .card
类,以确保实用程序仍可覆盖它。
如果您编写了大量 CSS 并将其组织到多个文件中,请确保在使用 Tailwind 处理它们之前将这些文件合并到单个样式表中,否则您会看到有关使用 @layer
而没有相应的 @tailwind
指令的错误。
最简单的方法是使用 postcss-import 插件:
module.exports = {
plugins: {
'postcss-import': {},
tailwindcss: {},
autoprefixer: {},
}
}
在我们的 build-time imports 文档中了解更多信息。
Vue 和 Svelte 等组件框架支持在每个组件文件中的 <style>
块内添加每个组件样式。
虽然您可以在这样的组件样式中使用 @apply
和 theme
之类的功能,但是 @layer
指令将不起作用,并且您会看到有关使用 @layer
而没有匹配的 @tailwind
指令的错误:
不要在组件样式中使用 @layer
<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
<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 的实用程序代替组件样式
<div class="bg-white rounded-lg p-6 shadow-xl">
<slot></slot>
</div>
您还可以使用 Tailwind 的插件系统向您的项目添加自定义样式,而不是使用 CSS 文件:
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',
}
})
})
]
}
在 Plugins 文档中了解有关编写自己的插件的更多信息。