Tailwind CSS v3.1:你想来点刺激的吗?来吧,让我们嗨起来!

Adam Wathan

自从我们发布了 Tailwind CSS v3.0 以来,已经过去了大约六个月。尽管此后我们一直在代码库中收集许多小的改进,但我们仍然没有那个特别的功能让你说“好吧,是时候发布了”

然后,在几周前的一个随机的星期六晚上,我在 Discord 中与 Robin 讨论如何使用 :has 和文档中更深层的类来定位 html 元素,并解释了如果我们添加对任意变体的支持会是什么样子——这是我一年多以来一直想解决的问题

Adam Wathan: I think if we do arbitrary variants, the syntax should just be that exact thing, '[html:has(&)]:bg-blue-500'. Feel like that is pretty flexible, like anything you can do with a real variant you can also do with an arbitrary variant since they are the same thing. '[&>*:not(:first-child)]:pl-4'.
Robin: This is going to break my brain haha because '[html:has(&)]:bg-blue-500' would be used as a literal inside the '&'. That in combination with other variants... 🤯.
Adam Wathan: 😅 it'll be a brain melter for sure. The CSS would be this lol 'html:has([html:has(&)]:bg-blue-500 {"{"} background: blue 500 }'.
Robin: exactly haha. ok, now I want to try that brb.

二十分钟后,Robin 就有了一个可行的概念验证(只用了六行代码!),在 Jordan 又花了一个小时左右的时间在我们的类检测引擎中进行正则表达式的奇迹操作后,任意变体诞生了,我们有了值得发布的功能。

所以,Tailwind CSS v3.1 就此诞生了!有关每个修复和改进的完整列表,请查看发布说明,但以下是重点

通过从 npm 安装最新版本的 tailwindcss 来升级您的项目

npm install tailwindcss@latest

或者启动 Tailwind Play,在浏览器中试用所有新功能。


第一方 TypeScript 类型

我们现在为所有在使用 Tailwind 时使用的 JS API 提供类型,最值得注意的是 tailwind.config.js 文件。这意味着您可以获得各种有用的 IDE 支持,并且可以更轻松地更改配置,而无需过多参考文档。

要进行设置,只需在您的配置定义上方添加类型注释

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
// ...
],
theme: {
extend: {},
},
plugins: [],
};

如果您是一个 TypeScript 爱好者,您可能会喜欢研究实际的 类型定义——其中有很多有趣的东西,以支持这样一个可能复杂的对象。

CLI 中内置 CSS 导入支持

如果您使用我们的 CLI 工具来编译 CSS,postcss-import 现在已内置,因此您可以将自定义 CSS 组织到多个文件中,而无需任何额外的配置。

@import "tailwindcss/base";
@import "./select2-theme.css";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

如果您不使用我们的 CLI 工具,而是将 Tailwind 用作 PostCSS 插件,那么您仍然需要像安装和配置 autoprefixer 一样自己安装和配置 postcss-import,但如果您正在使用我们的 CLI 工具,那么现在这将完全正常工作。

如果您正在使用我们的 独立 CLI 并且不想安装任何 node 依赖项,这将特别方便。

使用 theme 函数时更改颜色不透明度

我认为没有很多人知道这一点,但 Tailwind 向您的 CSS 文件公开了一个 theme() 函数,让您可以从配置文件中获取值——有点像将它们变成您可以重用的变量。

select2-theme.css
.select2-dropdown {
border-radius: theme(borderRadius.lg);
background-color: theme(colors.gray.100);
color: theme(colors.gray.900);
}
/* ... */

但一个限制是,您无法调整以这种方式获取的任何颜色的 alpha 通道。因此,在 v3.1 中,我们添加了对使用斜杠语法来调整不透明度的支持,就像您可以使用现代 rgbhsl CSS 颜色函数一样

select2-theme.css
.select2-dropdown {
border-radius: theme(borderRadius.lg);
background-color: theme(colors.gray.100 / 50%);
color: theme(colors.gray.900);
}
/* ... */

我们使这适用于您的 tailwind.config.js 文件中的 theme 函数

tailwind.config.js
module.exports = {
content: [
// ...
],
theme: {
extend: {
colors: ({ theme }) => ({
primary: theme("colors.blue.500"),
"primary-fade": theme("colors.blue.500 / 75%"),
}),
},
},
plugins: [],
};

您甚至可以在任意值中使用这些东西,这非常疯狂——老实说,对于奇怪的自定义渐变等东西非常有用

<div class="bg-[image:linear-gradient(to_right,theme(colors.red.500)_75%,theme(colors.red.500/25%))]">
<!-- ... -->
</div>

一切都是为了避免编辑 CSS 文件,对吧?

更简单的 CSS 变量颜色配置

如果您喜欢将颜色定义和配置为 CSS 变量,您现在可能在 tailwind.config.js 文件中遇到一些可怕的样板代码,例如这样

tailwind.config.js
function withOpacityValue(variable) {
return ({ opacityValue }) => {
if (opacityValue === undefined) {
return `rgb(var(${variable}))`;
}
return `rgb(var(${variable}) / ${opacityValue})`;
};
}
module.exports = {
theme: {
colors: {
primary: withOpacityValue("--color-primary"),
secondary: withOpacityValue("--color-secondary"),
// ...
},
},
};

在 v3.1 中,我们通过添加对使用格式字符串而不是必须使用函数来定义颜色的支持,使这种情况变得不那么糟糕

tailwind.config.js
module.exports = {
theme: {
colors: {
primary: "rgb(var(--color-primary) / <alpha-value>)",
secondary: "rgb(var(--color-secondary) / <alpha-value>)",
// ...
},
},
};

您可以只编写一个带有 <alpha-value> 占位符的字符串,而不是编写一个接收 opacityValue 参数的函数,Tailwind 将根据实用程序将该占位符替换为正确的 alpha 值。

如果您以前没有见过任何这些内容,请查看我们更新的 使用 CSS 变量 文档以获取更多详细信息。

边框间距实用工具

我们为 border-spacing 属性添加了新的实用工具集,因此您可以在使用 separate borders 时控制表格边框之间的间距

城市
印第安纳州印第安纳波利斯
俄亥俄州哥伦布
密歇根州底特律
<table class="border-separate border-spacing-2 ...">
<thead>
<tr>
<th class="border border-slate-300 ...">State</th>
<th class="border border-slate-300 ...">City</th>
</tr>
</thead>
<tbody>
<tr>
<td class="border border-slate-300 ...">Indiana</td>
<td class="border border-slate-300 ...">Indianapolis</td>
</tr>
<!-- ... -->
</tbody>
</table>

我知道你在想什么——“我这辈子从来没有想过要构建一个看起来像那样的表格……”——但请听我说一秒钟!

一个实际上超级有用的情况是,当构建带有粘性表头行的表格时,你想要在标题下有一个持久的底部边框

滚动此表格以查看粘性表头行的效果

姓名角色
Courtney Henry管理员
Tom Cook成员
Whitney Francis管理员
Leonard Krasner所有者
Floyd Miles成员
Emily Selman成员
Kristin Watson管理员
Emma Dorsey成员
Alicia Bell管理员
Jenny Wilson所有者
Anna Roberts成员
Benjamin Russel成员
Jeffrey Webb管理员
Kathryn Murphy成员
<table class="border-separate border-spacing-0">
<thead class="bg-gray-50">
<tr>
<th class="sticky top-0 z-10 border-b border-gray-300 ...">Name</th>
<th class="sticky top-0 z-10 border-b border-gray-300 ...">Email</th>
<th class="sticky top-0 z-10 border-b border-gray-300 ...">Role</th>
</tr>
</thead>
<tbody class="bg-white">
<tr>
<td class="border-b border-gray-200 ...">Courtney Henry</td>
<td class="border-b border-gray-200 ...">courtney.henry@example.com</td>
<td class="border-b border-gray-200 ...">Admin</td>
</tr>
<!-- ... -->
</tbody>
</table>

您可能会认为您可以在这里使用 border-collapse,因为您实际上不希望边框之间有任何间距,但您就错了。如果没有 border-separateborder-spacing-0,边框将滚动离开,而不是粘在标题下方。CSS 很有趣,不是吗?

查看 边框间距文档 以获取更多详细信息。

启用和可选变体

我们为 :enabled:optional 伪类添加了新的变体,它们在表单元素启用和可选时定位它们。

“但是 Adam,我为什么要用这些,启用和可选甚至都不是状态,它们是默认值。你真的做网站吗?”

哎哟,这很伤人,因为这是真的——我现在几乎只写电子邮件,并在 GitHub 上一遍又一遍地回答相同的问题。

但请查看这个禁用的按钮示例

<button type="button" class="bg-indigo-500 hover:bg-indigo-400 disabled:opacity-75 ..." disabled>Processing...</button>

请注意,当您将鼠标悬停在按钮上时,即使按钮已禁用,背景颜色仍然会改变?在此版本之前,您通常会像这样修复它

<button
type="button"
class="bg-indigo-500 hover:bg-indigo-400 disabled:opacity-75 disabled:hover:bg-indigo-500 ..."
disabled
>
Processing...
</button>

但是使用新的 enabled 修饰符,您可以像这样编写它

<button type="button" class="bg-indigo-500 hover:enabled:bg-indigo-400 disabled:opacity-75 ..." disabled>
Processing...
</button>

我们没有在按钮禁用时将悬停颜色覆盖回默认颜色,而是将 hoverenabled 变体结合起来,以便在按钮禁用时不应用悬停样式。我认为这样更好!

这是一个结合了新的 optional 修饰符和我们的 兄弟状态功能 的示例,用于隐藏非必填字段的“必填”提示

必填
必填
<form>
<div>
<label for="email" ...>Email</label>
<div>
<input required class="peer ..." id="email" />
<div class="peer-optional:hidden ...">Required</div>
</div>
</div>
<div>
<label for="name" ...>Name</label>
<div>
<input class="peer ..." id="name" />
<div class="peer-optional:hidden ...">Required</div>
</div>
</div>
<!-- ... -->
</form>

这使您可以对所有表单组使用相同的标记,并让 CSS 处理所有条件渲染,而不是自己处理。有点简洁!

Prefers-contrast 变体

您知道有 prefers-contrast 媒体查询吗?好吧,确实有,现在 Tailwind 开箱即用地支持它。

当用户请求更多或更少对比度时,使用新的 contrast-morecontrast-less 变体来修改您的设计,通常是通过操作系统辅助功能首选项,例如 macOS 上的“增加对比度”。

尝试在您的开发者工具中模拟 `prefers-contrast: more` 以查看更改

我们需要这个来窃取您的身份。

<form>
<label class="block">
<span class="block text-sm font-medium text-slate-700">Social Security Number</span>
<input
class="border-slate-200 placeholder-slate-400 contrast-more:border-slate-400 contrast-more:placeholder-slate-500"
/>
<p class="mt-2 text-sm text-slate-600 opacity-10 contrast-more:opacity-100">We need this to steal your identity.</p>
</label>
</form>

我为这个写了一些 文档,但老实说,我在这里写的比那里写的还多。

样式化原生对话框背景

有一个非常新的 HTML <dialog> 元素,具有令人惊讶的良好 浏览器支持,如果您喜欢走在前沿,值得一试。

对话框具有这个新的 ::backdrop 伪元素,它在对话框打开时呈现,Tailwind CSS v3.1 添加了一个新的 backdrop 修饰符,您可以使用它来样式化这个宝贝

<dialog class="backdrop:bg-slate-900/50 ...">
<form method="dialog">
<!-- ... -->
<button value="cancel">Cancel</button>
<button>Submit</button>
</form>
</dialog>

如果您想更深入地研究这个东西,我建议阅读 MDN Dialog 文档 ——这很令人兴奋,但有很多东西需要了解。

任意值,但用于变体

好吧,这个对我来说才是真正的亮点——您知道我们如何为您提供 addVariant API 来创建您自己的自定义变体吗?

tailwind.config.js
const plugin = require("tailwindcss/plugin");
module.exports = {
// ...
plugins: [
plugin(function ({ addVariant }) {
addVariant("third", "&:nth-child(3)");
}),
],
};

……您也知道我们如何使用 任意值 来直接在 HTML 中使用您想要的任何值吗?

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

好吧,Tailwind CSS v3.1 引入了 任意变体,让您可以直接在 HTML 中创建自己的临时变体

<div class="[&:nth-child(3)]:py-0">
<!-- ... -->
</div>

这对于感觉需要参数化的变体非常有用,例如,如果浏览器使用 @supports 查询支持特定的 CSS 功能,则添加样式

<div
class="bg-white [@supports(backdrop-filter:blur(0))]:bg-white/50 [@supports(backdrop-filter:blur(0))]:backdrop-blur"
>
<!-- ... -->
</div>

您甚至可以使用此功能通过任意变体(如 [&>*])来定位子元素

  • Kristen Ramos

    kristen.ramos@example.com

  • Floyd Miles

    floyd.miles@example.com

  • Courtney Henry

    courtney.henry@example.com

<ul role="list" class="space-y-4 [&>*]:rounded-lg [&>*]:bg-white [&>*]:p-4 [&>*]:shadow">
<li class="flex">
<img class="h-10 w-10 rounded-full" src="..." alt="" />
<div class="ml-3 overflow-hidden">
<p class="text-sm font-medium text-slate-900">Kristen Ramos</p>
<p class="truncate text-sm text-slate-500">kristen.ramos@example.com</p>
</div>
</li>
<!-- ... -->
</ul>

您甚至可以样式化第二个子 li 中的 div 内的第一个 p,但仅在 hover 时才样式化

尝试将鼠标悬停在文本“Floyd Miles”上

  • Kristen Ramos

    kristen.ramos@example.com

  • Floyd Miles

    floyd.miles@example.com

  • Courtney Henry

    courtney.henry@example.com

<ul
role="list"
class="space-y-4 [&>*]:rounded-lg [&>*]:bg-white [&>*]:p-4 [&>*]:shadow hover:[&>li:nth-child(2)>div>p:first-child]:text-indigo-500"
>
<!-- ... -->
<li class="flex">
<img class="h-10 w-10 rounded-full" src="..." alt="" />
<div class="ml-3 overflow-hidden">
<p class="text-sm font-medium text-slate-900">Floyd Miles</p>
<p class="truncate text-sm text-slate-500">floyd.miles@example.com</p>
</div>
</li>
<!-- ... -->
</ul>

现在应该这样做吗?可能不应该经常这样做,但老实说,当尝试样式化您无法直接更改的 HTML 时,它可能是一个非常有用的逃生舱口。这是一把锋利的刀,但最好的厨师不会用安全剪刀准备食物。

稍微试用一下它们,我敢打赌您会发现它们在需要时是一个很棒的工具。我们在我们正在开发的新网站模板中的一些棘手的地方使用了它们,并且体验比创建自定义类要好得多。


这就是 Tailwind CSS v3.1!这只是一个次要版本更改,因此没有破坏性更改,您应该可以通过安装最新版本来更新您的项目

npm install tailwindcss@latest

有关包括错误修复和我在这里没有谈到的一些次要改进的完整更改列表,请深入研究 GitHub 上的 发布说明

我已经对 Tailwind CSS v3.2 有了很多想法(甚至最终可能会有文本阴影?!),但现在我们正在努力将这些新的 网站模板 推向终点线。请期待在接下来的一两周内就该主题发布另一篇更新!

直接将我们的所有更新发送到您的收件箱。
注册我们的新闻通讯。

版权所有 © 2025 Tailwind Labs Inc.·商标政策