Tailwind CSS v3.1: 你想要发疯吗?来吧,我们一起发疯吧!

Adam Wathan

自从我们发布了 Tailwind CSS v3.0,已经过去了六个月,尽管我们自那时以来在代码库中收集了许多小改进,但我们还没有 that-one-feature 让你说 "好吧,是时候发布了"

然后在几周前的一个随机星期六晚上,我在 Discord 中和 Robin 聊天,讨论如何使用 :has 选择器和文档中更深层的类来选择 html 元素,并解释了如果我们添加对任意变体的支持会是什么样子——这是我想处理的事情已经超过一年了:

Adam Wathan: 我认为如果我们做任意变体,语法应该就是这样 '[html:has(&)]:bg-blue-500'。感觉这很灵活,就像你用真正的变体能做的任何事情,你也可以用任意变体做,因为它们是同一回事。 '[&>*:not(:first-child)]:pl-4'。
Robin: 这会弄乱我的脑子哈哈,因为 '[html:has(&)]:bg-blue-500' 会被用作 '&' 中的字面量。结合其他变体... 🤯。
Adam Wathan: 😅,这肯定会神经凌乱。CSS 会是这样的,哈哈 'html:has([html:has(&)]:bg-blue-500 {"{"} background: blue 500 }'。
Robin: 完全正确哈哈。好的,现在我想试试,稍等。

二十分钟后,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 并且不想安装任何节点依赖的用户来说尤其便利。

使用主题函数时更改颜色的不透明度

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

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>)",
// ...
},
},
};

不再需要编写接收 opacityValue 参数的函数,你只需要编写一个带有 <alpha-value> 占位符的字符串,Tailwind 将会根据工具类替换该占位符为正确的 alpha 值。

如果你以前没有见过这些,请查看我们更新的 使用 CSS 变量 文档以获取更多细节。

边框间距工具

我们添加了一组新的工具用于 border-spacing 属性,因此你可以控制在使用 分离边框 时表格边框之间的空间:

城市
印第安纳州印第安纳波利斯
俄亥俄州哥伦布
密歇根州底特律
<table class="border-separate border-spacing-2 ...">
<thead>
<tr>
<th class="border border-slate-300 ..."></th>
<th class="border border-slate-300 ...">城市</th>
</tr>
</thead>
<tbody>
<tr>
<td class="border border-slate-300 ...">印第安纳州</td>
<td class="border border-slate-300 ...">印第安纳波利斯</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 ...">姓名</th>
<th class="sticky top-0 z-10 border-b border-gray-300 ...">邮箱</th>
<th class="sticky top-0 z-10 border-b border-gray-300 ...">角色</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 ...">管理员</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>正在处理...</button>

注意在你将鼠标悬停在按钮上时,即使它被禁用,背景颜色仍然会改变?在这个版本之前,通常你会这样解决这个问题:

<button
type="button"
class="bg-indigo-500 hover:bg-indigo-400 disabled:opacity-75 disabled:hover:bg-indigo-500 ..."
disabled
>
正在处理...
</button>

但使用新的 enabled 修饰符,你可以这样编写:

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

我们不再在按钮被禁用时将悬停颜色重置为默认色,而是组合 hoverenabled 变体,使按钮在禁用的情况下根本不应用悬停样式。我觉得这样更好!

这是一个结合新的 optional 修饰符和我们的 同胞状态特征 的示例,以隐藏对非必需字段的 "必填" 提示:

必填
必填
<form>
<div>
<label for="email" ...>邮箱</label>
<div>
<input required class="peer ..." id="email" />
<div class="peer-optional:hidden ...">必填</div>
</div>
</div>
<div>
<label for="name" ...>姓名</label>
<div>
<input class="peer ..." id="name" />
<div class="peer-optional:hidden ...">必填</div>
</div>
</div>
<!-- ... -->
</form>

这让你可以对所有表单组使用相同的标记,并让 CSS 处理所有条件渲染,而不是自己处理。真是不错的主意!

优先对比变体

你知道有 prefers-contrast 媒体查询吗?其实是有的,Tailwind 现在开箱即用支持它。

使用新的 contrast-morecontrast-less 变体,当用户请求更多或更少的对比度时修改设计,通常通过操作系统的可访问性首选项,如 macOS 上的 “增加对比度”。

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

我们需要这个以窃取你的身份。

<form>
<label class="block">
<span class="block text-sm font-medium text-slate-700">社会安全号码</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">我们需要这个以窃取你的身份。</p>
</label>
</form>

我写过 一些文档,但老实说,我在这里写的更多。

样式原生对话框背景

有一个相当新的 HTML <dialog> 元素,支持相当不错的 浏览器,如果你喜欢在前沿探索,值得玩玩。

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

<dialog class="backdrop:bg-slate-900/50 ...">
<form method="dialog">
<!-- ... -->
<button value="cancel">取消</button>
<button>提交</button>
</form>
</dialog>

如果您想深入了解这个东西,我建议阅读 MDN 对话框文档——这都是令人兴奋的内容,但有很多内容需要掌握。

变体的任意值

好了,这个对我来说是真正的亮点——你知道我们给你提供了 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 className="flex">
<img className="h-10 w-10 rounded-full" src="..." alt="" />
<div className="ml-3 overflow-hidden">
<p className="text-sm font-medium text-slate-900">Kristen Ramos</p>
<p className="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 className="flex">
<img className="h-10 w-10 rounded-full" src="..." alt="" />
<div className="ml-3 overflow-hidden">
<p className="text-sm font-medium text-slate-900">Floyd Miles</p>
<p className="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 的想法 (也许最终能加入文本阴影?!),但目前我们正在努力推进这些新 网站模板 完成。请在接下来的一两个星期内关注该主题的其他更新!

Get all of our updates directly to your inbox.
Sign up for our newsletter.