自从我们发布了 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.](/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fdiscord-message.225e322a.png&w=3840&q=75)
二十分钟后,Robin 就有了一个可行的概念验证(只用了六行代码!),在 Jordan 又花了一个小时左右的时间在我们的类检测引擎中进行正则表达式的奇迹操作后,任意变体诞生了,我们有了值得发布的功能。
所以,Tailwind CSS v3.1 就此诞生了!有关每个修复和改进的完整列表,请查看发布说明,但以下是重点
- 第一方 TypeScript 类型
- CLI 中内置 CSS 导入支持
- 使用 theme 函数时更改颜色不透明度
- 更简单的 CSS 变量颜色配置
- 边框间距实用工具
- 启用和可选变体
- Prefers-contrast 变体
- 样式化原生对话框背景
- 任意值,但用于变体
通过从 npm 安装最新版本的 tailwindcss
来升级您的项目
npm install tailwindcss@latest
或者启动 Tailwind Play,在浏览器中试用所有新功能。
第一方 TypeScript 类型
我们现在为所有在使用 Tailwind 时使用的 JS API 提供类型,最值得注意的是 tailwind.config.js
文件。这意味着您可以获得各种有用的 IDE 支持,并且可以更轻松地更改配置,而无需过多参考文档。
要进行设置,只需在您的配置定义上方添加类型注释
/** @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-dropdown { border-radius: theme(borderRadius.lg); background-color: theme(colors.gray.100); color: theme(colors.gray.900);}/* ... */
但一个限制是,您无法调整以这种方式获取的任何颜色的 alpha 通道。因此,在 v3.1 中,我们添加了对使用斜杠语法来调整不透明度的支持,就像您可以使用现代 rgb
和 hsl
CSS 颜色函数一样
.select2-dropdown { border-radius: theme(borderRadius.lg); background-color: theme(colors.gray.100 / 50%); color: theme(colors.gray.900);}/* ... */
我们使这适用于您的 tailwind.config.js
文件中的 theme
函数
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
文件中遇到一些可怕的样板代码,例如这样
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 中,我们通过添加对使用格式字符串而不是必须使用函数来定义颜色的支持,使这种情况变得不那么糟糕
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 | courtney.henry@example.com | 管理员 |
Tom Cook | tom.cook@example.com | 成员 |
Whitney Francis | whitney.francis@example.com | 管理员 |
Leonard Krasner | leonard.krasner@example.com | 所有者 |
Floyd Miles | floyd.miles@example.com | 成员 |
Emily Selman | emily.selman@example.com | 成员 |
Kristin Watson | kristin.watson@example.com | 管理员 |
Emma Dorsey | emma.dorsey@example.com | 成员 |
Alicia Bell | alicia.bell@example.com | 管理员 |
Jenny Wilson | jenny.wilson@example.com | 所有者 |
Anna Roberts | anna.roberts@example.com | 成员 |
Benjamin Russel | benjamin.russel@example.com | 成员 |
Jeffrey Webb | jeffrey.webb@example.com | 管理员 |
Kathryn Murphy | kathryn.murphy@example.com | 成员 |
<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-separate
和 border-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>
我们没有在按钮禁用时将悬停颜色覆盖回默认颜色,而是将 hover
和 enabled
变体结合起来,以便在按钮禁用时不应用悬停样式。我认为这样更好!
这是一个结合了新的 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-more
和 contrast-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 来创建您自己的自定义变体吗?
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 有了很多想法(甚至最终可能会有文本阴影?!),但现在我们正在努力将这些新的 网站模板 推向终点线。请期待在接下来的一两周内就该主题发布另一篇更新!