Skip to content
全部文档

添加自定义样式

Best practices for adding your own custom styles in Tailwind projects.

使用框架时,最大的挑战往往是:当框架没有替你处理某件事时,你该怎么做。

Tailwind 从一开始就按可扩展、可定制来设计,无论你在构建什么,都不会觉得自己在和框架较劲。

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

自定义主题

若要更改调色板、间距比例、字体比例或断点等,请在 CSS 中用 @theme 指令添加自定义:

CSS
css
@theme {
  --font-display: "Satoshi", "sans-serif";

  --breakpoint-3xl: 120rem;

  --color-avocado-100: oklch(0.99 0 0);
  --color-avocado-200: oklch(0.98 0.04 113.22);
  --color-avocado-300: oklch(0.94 0.11 115.03);
  --color-avocado-400: oklch(0.92 0.19 114.08);
  --color-avocado-500: oklch(0.84 0.18 117.33);
  --color-avocado-600: oklch(0.53 0.12 118.34);

  --ease-fluid: cubic-bezier(0.3, 0, 0, 1);
  --ease-snappy: cubic-bezier(0.2, 0, 0, 1);

  /* ... */
}

更多自定义主题的内容,见主题变量文档

使用任意值

大多数精心打磨的设计,用一套受约束的设计令牌就能完成;偶尔你需要突破这些约束,才能做到像素级精确。

当你确实需要类似 top: 117px 才能把背景图放到正确位置时,用 Tailwind 的方括号记法,按任意值即时生成类名:

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

这基本上类似于内联样式,但一大好处是可以和 hover 这类交互修饰符、以及 lg 这类响应式修饰符组合使用:

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

这对框架中的一切都适用,包括背景色、字号、伪元素内容等:

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

如果任意值引用的是 CSS 变量,可以使用自定义属性语法:

HTML
html
<!-- [!code classes:fill-(--my-brand-color)] -->
<div class="fill-(--my-brand-color) ...">
  <!-- ... -->
</div>

这只是 fill-[var(--my-brand-color)] 的简写,会自动帮你加上 var() 函数。

任意属性

如果要用的 CSS 属性 Tailwind 没有开箱即用的工具类,也可以用方括号记法写完全任意的 CSS:

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

真的很像内联样式,但同样的好处是你可以使用修饰符:

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

这对 CSS 变量也很有用,尤其是它们需要在不同条件下变化时:

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

任意变体

任意变体类似于任意值,但用于即时修改选择器:就像内置伪类变体 hover:{utility} 或响应式变体 md:{utility} 那样,只不过直接在 HTML 里用方括号记法。

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

更多内容见任意变体文档。

处理空白

当任意值需要包含空格时,改用下划线(_),Tailwind 会在构建时自动把它转成空格:

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

在下划线很常见、但空格不合法的场景(例如 URL)中,Tailwind 会保留下划线,而不会把它转成空格:

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

极少数情况下,你确实需要下划线,但又因为空格也合法而会产生歧义,这时用反斜杠转义下划线,Tailwind 就不会把它转成空格:

HTML
html
<!-- [!code classes:before:content-['hello\_world']] -->
<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
html
<!-- [!code classes:text-[22px],text-[#bada55]] -->
<!-- Will generate a font-size utility -->
<div class="text-[22px]">...</div>

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

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

HTML
html
<!-- [!code classes:text-(--my-var)] -->
<div class="text-(--my-var)">...</div>

这时,可以在值前面加上 CSS 数据类型,向 Tailwind「提示」底层类型:

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

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

使用自定义 CSS

虽然 Tailwind 旨在覆盖大部分样式需求,但需要时你完全可以写普通 CSS:

CSS
css
@import "tailwindcss";

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

添加基础样式

如果只是想给页面设一些默认值(如文字颜色、背景色或字体系列),最简单的办法是给 htmlbody 元素加上一些类:

HTML
html
<!-- [!code classes:bg-gray-100,font-serif,text-gray-900] -->
<!doctype html>
<html lang="en" class="bg-gray-100 font-serif text-gray-900">
  <!-- ... -->
</html>

这样基础样式决策就和其余样式一起放在标记里,而不是藏在单独的文件中。

如果要为特定 HTML 元素添加自己的默认基础样式,用 @layer 指令把这些样式加到 Tailwind 的 base 层:

CSS
css
@layer base {
  h1 {
    font-size: var(--text-2xl);
  }

  h2 {
    font-size: var(--text-xl);
  }
}

添加组件类

把更复杂、但仍希望能用工具类覆盖的类放到 components 层。

传统上这类类名会是 cardbtnbadge 之类。

CSS
css
@layer components {
  .card {
    background-color: var(--color-white);
    border-radius: var(--radius-lg);
    padding: --spacing(6);
    box-shadow: var(--shadow-xl);
  }
}

把组件类定义在 components 层后,必要时仍可用工具类覆盖它们:

HTML
html
<!-- [!code classes:card,rounded-none] -->
<!-- Will look like a card, but with square corners -->
<div class="card rounded-none">
  <!-- ... -->
</div>

使用 Tailwind 时,这类类可能没有你想的那么常用。关于我们的建议,请阅读管理重复指南。

components 层也很适合放置第三方组件的自定义样式:

CSS
css
@layer components {
  .select2-dropdown {
    /* ... */
  }
}

使用变体

在自定义 CSS 中用 @variant 指令应用 Tailwind 变体:

app.css
css
.my-element {
  background: white;

  @variant dark {
    background: black;
  }
}
Compiled CSS
css
.my-element {
  background: white;

  @media (prefers-color-scheme: dark) {
    background: black;
  }
}

如果要同时应用多个变体,用和 HTML 中一样的语法把它们叠在一起:

app.css
css
.my-element {
  background: white;

  @variant hover:focus {
    background: black;
  }
}
Compiled CSS
css
.my-element {
  background: white;

  &:hover {
    @media (hover: hover) {
      &:focus {
        background: black;
      }
    }
  }
}

要为多个变体应用相同样式,用逗号分隔各个变体:

app.css
css
.my-element {
  background: white;

  @variant hover, focus {
    background: black;
  }
}
Compiled CSS
css
.my-element {
  background: white;

  &:hover {
    @media (hover: hover) {
      background: black;
    }
  }

  &:focus {
    background: black;
  }
}

添加自定义工具类

简单工具类

除了使用 Tailwind 自带的工具类,你也可以添加自己的自定义工具类。当你想用某个 CSS 特性,而 Tailwind 没有开箱即用的工具类时,这会很有用。

@utility 指令向项目添加自定义工具类:

CSS
css
@utility content-auto {
  content-visibility: auto;
}

现在可以在 HTML 中使用这个工具类:

HTML
html
<!-- [!code classes:content-auto] -->
<div class="content-auto">
  <!-- ... -->
</div>

它也适用于 hoverfocuslg 等变体:

HTML
html
<!-- [!code classes:hover:content-auto] -->
<div class="hover:content-auto">
  <!-- ... -->
</div>

自定义工具类会自动插入 utilities 层,与框架内置工具类放在一起。

复杂工具类

如果自定义工具类比单个类名更复杂,用嵌套来定义:

CSS
css
@utility scrollbar-hidden {
  &::-webkit-scrollbar {
    display: none;
  }
}

函数式工具类

除了用 @utility 注册简单工具类,还可以注册接受参数的函数式工具类:

CSS
css
@utility tab-* {
  /* prettier-ignore */
  tab-size: --value(--tab-size-*);
}

特殊函数 --value() 用于解析工具类的值。

匹配主题值

--value(--theme-key-*) 语法,对照一组主题键解析工具类的值:

CSS
css
@theme {
  --tab-size-2: 2;
  --tab-size-4: 4;
  --tab-size-github: 8;
}

@utility tab-* {
  /* prettier-ignore */
  tab-size: --value(--tab-size-*);
}

这会匹配 tab-2tab-4tab-github 这类工具类。

裸值

要把值解析为裸值,使用 --value({type}) 语法,其中 {type} 是你希望用来校验裸值的数据类型:

CSS
css
@utility tab-* {
  tab-size: --value(integer);
}

这会匹配 tab-1tab-76 这类工具类。

可用的裸值数据类型有:numberintegerratiopercentage

字面量值

要支持字面量值,使用 --value('literal') 语法(注意引号):

CSS
css
@utility tab-* {
  tab-size: --value("inherit", "initial", "unset");
}

这会匹配 tab-inherittab-initialtab-unset 这类工具类。

任意值

要支持任意值,使用 --value([{type}]) 语法(注意方括号),告诉 Tailwind 哪些类型可作为任意值:

CSS
css
@utility tab-* {
  tab-size: --value([integer]);
}

这会匹配 tab-[1]tab-[76] 这类工具类。

可用的任意值数据类型有:absolute-sizeanglebg-sizecolorfamily-namegeneric-nameimageintegerlengthline-widthnumberpercentagepositionratiorelative-sizeurlvector*

同时支持主题值、裸值和任意值

--value() 函数的三种形式都可以作为多条声明写在同一条规则里,解析失败的声明会在输出中被省略:

CSS
css
@theme {
  --tab-size-github: 8;
}

@utility tab-* {
  tab-size: --value([integer]);
  tab-size: --value(integer);
  /* prettier-ignore */
  tab-size: --value(--tab-size-*);
}

这样就可以在不同情况下区别处理值,例如把裸整数转成百分比:

CSS
css
@utility opacity-* {
  opacity: --value([percentage]);
  opacity: calc(--value(integer) * 1%);
  /* prettier-ignore */
  opacity: --value(--opacity-*);
}

如果你不需要在不同情况下区别处理返回值,--value() 也可以接受多个参数,并从左到右解析:

CSS
css
@theme {
  --tab-size-github: 8;
}

@utility tab-* {
  /* prettier-ignore */
  tab-size: --value(--tab-size-*, integer, [integer]);
}

@utility opacity-* {
  opacity: calc(--value(integer) * 1%);
  /* prettier-ignore */
  opacity: --value(--opacity-*, [percentage]);
}

默认值

--value() 里使用 --default(),以便在工具类未显式传值时使用默认值:

CSS
css
/* [!code word:--default(4)] */
@utility tab-* {
  tab-size: --value(integer, --default(4));
}

这既匹配 tab-2tab-4,也匹配只用默认值 4tab

Compiled CSS
css
.tab {
  tab-size: 4;
}

.tab-2 {
  tab-size: 2;
}

--default() 也可以用在 --modifier() 里,在没有修饰符时提供默认值:

CSS
css
/* [!code word:--default(1)] */
@utility tab-* {
  tab-size: --value(integer);
  line-height: --modifier(integer, --default(1));
}

这会匹配 tab-2/3(line-height 为 3),以及 tab-2(line-height 为 1)。

负值

要支持负值,请把正、负工具类分别注册为独立声明:

CSS
css
@utility inset-* {
  inset: --spacing(--value(integer));
  inset: --value([percentage], [length]);
}

@utility -inset-* {
  inset: --spacing(--value(integer) * -1);
  inset: calc(--value([percentage], [length]) * -1);
}

修饰符

修饰符用 --modifier() 处理,它的工作方式和 --value() 完全一样,只不过作用在(若存在的)修饰符上:

CSS
css
@utility text-* {
  /* prettier-ignore */
  font-size: --value(--text-*, [length]);
  /* prettier-ignore */
  line-height: --modifier(--leading-*, [length], [*]);
}

如果没有修饰符,任何依赖修饰符的声明都不会出现在输出中。

分数

处理分数时,我们依赖 CSS 的 ratio 数据类型。如果把它和 --value() 一起用,就是在告诉 Tailwind 把值和修饰符当作一个整体:

CSS
css
@utility aspect-* {
  /* [!code word:ratio, \[ratio\]] */
  /* prettier-ignore */
  aspect-ratio: --value(--aspect-ratio-*, ratio, [ratio]);
}

这会匹配 aspect-squareaspect-3/4aspect-[7/9] 这类工具类。

添加自定义变体

除了使用 Tailwind 自带的变体,还可以用 @custom-variant 指令添加自己的自定义变体:

css
@custom-variant theme-midnight {
  &:where([data-theme="midnight"] *) {
    @slot;
  }
}

现在可以在 HTML 中使用 theme-midnight:<utility> 变体:

html
<!-- [!code classes:theme-midnight:bg-black] -->
<html data-theme="midnight">
  <button class="theme-midnight:bg-black ..."></button>
</html>

不需要嵌套时,可以用简写语法创建变体:

css
@custom-variant theme-midnight (&:where([data-theme="midnight"] *));

自定义变体有多条规则时,可以把它们互相嵌套:

css
@custom-variant any-hover {
  @media (any-hover: hover) {
    &:hover {
      @slot;
    }
  }
}

文档译文以 MIT 协议授权;原文版权归 Tailwind Labs。湘ICP备2026005453号-2