距离我们发布 Tailwind CSS v3.0 已经过去了大约六个月,尽管从那时起,我们已经在代码库中收集了很多小改进,但我们还没有那个让你想到 "好的,发布截止时间到了" 的功能。
¥It's been about six months since we released Tailwind CSS v3.0, and even though we've been collecting a lot of little improvements in the codebase since then, we just didn't have that-one-feature yet that makes you say "okay, it's release-cuttin' time".
几周前的一个周六晚上,我在 Discord 上与 Robin 讨论了使用 :has
和文档中更深层次的类来定位 html
元素的方法,并解释了我认为如果我们添加对任意变体的支持会是什么样子 - 这是我一年多来一直想解决的问题:
¥Then on a random Saturday night a couple of weeks ago, I was talking to Robin in our Discord about coming up with a way to target the html
element using :has
and a class deeper in the document, and explained how I thought it would look if we added support for arbitrary variants — something I've wanted to tackle for over a year:
![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 又在我们的类检测引擎中运用正则表达式,大约一个小时后,任意变体 诞生了,我们终于拥有了值得发布的功能。
¥Twenty minutes later Robin had a working proof of concept (in six lines of code!), and after another hour or so of Jordan performing regex miracles in our class detection engine, arbitrary variants were born and we had our release-worthy feature.
这就是 Tailwind CSS v3.1!如需查看所有修复和改进的完整列表,请查看 发行说明,以下是重点内容:
¥So here it is — Tailwind CSS v3.1! For a complete list of every fix and improvement check out the release notes, but here's the highlights:
通过从 npm 安装最新版本的 tailwindcss
来升级你的项目:
¥Upgrade your projects by installing the latest version of tailwindcss
from npm:
npm install tailwindcss@latest
或者启动 Tailwind Play,直接在浏览器中体验所有新功能。
¥Or spin up a Tailwind Play to play around with all of the new goodies right in the browser.
第一方 TypeScript 类型(First-party TypeScript types)
¥First-party TypeScript types
我们现在正在为所有使用 Tailwind 时使用的 JS API 提供类型,尤其是 tailwind.config.js
文件。这意味着你将获得各种有用的 IDE 支持,并且无需过多参考文档即可更轻松地更改配置。
¥We're now shipping types for all of our JS APIs you work with when using Tailwind, most notably the tailwind.config.js
file. This means you get all sorts of useful IDE support, and makes it a lot easier to make changes to your configuration without referencing the documentation quite as much.
要进行设置,只需在配置定义上方添加类型注释即可:
¥To set it up, just add the type annotation above your config definition:
/** @type {import('tailwindcss').Config} */module.exports = { content: [ // ... ], theme: { extend: {}, }, plugins: [],};
如果你是 TypeScript 的铁杆粉丝,你可能会喜欢探究 类型定义 本身 - 它有很多有趣的功能来支持这样一个潜在的复杂对象。
¥If you're a big TypeScript nerd you might enjoy poking around the actual type definitions — lots of interesting stuff going on there to support such a potentially complex object.
CLI 中内置 CSS 导入支持(Built-in support for CSS imports in the CLI)
¥Built-in support for CSS imports in the CLI
如果你使用我们的 CLI 工具编译 CSS,postcss-import
现已内置,因此你无需任何额外配置即可将自定义 CSS 组织到多个文件中。
¥If you're using our CLI tool to compile your CSS, postcss-import
is now baked right in so you can organize your custom CSS into multiple files without any additional configuration.
@import "tailwindcss/base";@import "./select2-theme.css";@import "tailwindcss/components";@import "tailwindcss/utilities";
如果你不使用我们的 CLI 工具,而是使用 Tailwind 作为 PostCSS 插件,你仍然需要像安装和配置 autoprefixer
一样自行安装和配置 postcss-import
。但如果你使用我们的 CLI 工具,现在就可以正常工作了。
¥If you're not using our CLI tool and instead using Tailwind as a PostCSS plugin, you'll still need to install and configure postcss-import
yourself just like you do with autoprefixer
, but if you are using our CLI tool this will totally just work now.
如果你正在使用我们的 独立 CLI 并且根本不想安装任何 Node 依赖,这将特别方便。
¥This is especially handy if you're using our standalone CLI and don't want to install any node dependencies at all.
使用主题功能时更改颜色不透明度(Change color opacity when using the theme function)
¥Change color opacity when using the theme function
我想很多人可能都不知道这一点,但 Tailwind 会向你的 CSS 文件公开一个 theme()
函数,让你可以从配置文件中获取值 - 有点像把它们转换成可以重用的变量。
¥I don't think tons of people know about this, but Tailwind exposes a theme()
function to your CSS files that lets you grab values from your config file — sort of turning them into variables that you can reuse.
.select2-dropdown { border-radius: theme(borderRadius.lg); background-color: theme(colors.gray.100); color: theme(colors.gray.900);}/* ... */
不过,这种方法有一个限制,那就是你无法调整通过这种方式获取的任何颜色的 Alpha 通道。因此,在 v3.1 中,我们添加了使用斜线语法调整不透明度的支持,就像使用现代 rgb
和 hsl
CSS 颜色函数一样:
¥One limitation though was that you couldn't adjust the alpha channel any colors you grabbed this way. So in v3.1 we've added support for using a slash syntax to adjust the opacity, like you can with the modern rgb
and hsl
CSS color functions:
.select2-dropdown { border-radius: theme(borderRadius.lg); background-color: theme(colors.gray.100 / 50%); color: theme(colors.gray.900);}/* ... */
我们也通过 tailwind.config.js
文件中的 theme
函数实现了此功能:
¥We've made this work with the theme
function in your tailwind.config.js
file, too:
module.exports = { content: [ // ... ], theme: { extend: { colors: ({ theme }) => ({ primary: theme("colors.blue.500"), "primary-fade": theme("colors.blue.500 / 75%"), }), }, }, plugins: [],};
你甚至可以将此功能设置为任意值,这非常疯狂 - 说实话,对于奇怪的自定义渐变和其他内容来说,它出奇地有用:
¥You can even use this stuff in arbitrary values which is pretty wild — honestly surprisingly useful for weird custom gradients and stuff:
<div class="bg-[image:linear-gradient(to_right,theme(colors.red.500)_75%,theme(colors.red.500/25%))]"> <!-- ... --></div>
有什么方法可以避免编辑 CSS 文件吗?
¥Anything to avoid editing a CSS file am I right?
更简单的 CSS 变量颜色配置(Easier CSS variable color configuration)
¥Easier CSS variable color configuration
如果你喜欢将颜色定义和配置为 CSS 变量,那么你的 tailwind.config.js
文件中现在可能有一些像这样糟糕的样板代码:
¥If you like to define and configure your colors as CSS variables, you probably have some horrible boilerplate like this in your tailwind.config.js
file right now:
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 中,我们通过添加使用格式字符串定义颜色的支持(无需使用函数),使这种方式变得不那么糟糕:
¥We've made this way less awful in v3.1 by adding support for defining your colors with a format string instead of having to use a function:
module.exports = { theme: { colors: { primary: "rgb(var(--color-primary) / <alpha-value>)", secondary: "rgb(var(--color-secondary) / <alpha-value>)", // ... }, },};
你无需编写接收 opacityValue
参数的函数,只需编写一个带有 <alpha-value>
占位符的字符串,Tailwind 就会根据实用程序将该占位符替换为正确的 Alpha 值。
¥Instead of writing a function that receives that opacityValue
argument, you can just write a string with an <alpha-value>
placeholder, and Tailwind will replace that placeholder with the correct alpha value based on the utility.
如果你之前没有了解过这些内容,请查看我们更新的 使用 CSS 变量 文档了解更多详情。
¥If you haven't seen any of this before, check out our updated Using CSS variables documentation for more details.
边框间距实用程序(Border spacing utilities)
¥Border spacing utilities
我们为 border-spacing
属性添加了一组新的实用程序,以便你在使用 单独的边界 时控制表格边框之间的间距:
¥We've added new set of utilities for the border-spacing
property, so you can control the space between table borders when using separate borders:
State | City |
---|---|
Indiana | Indianapolis |
Ohio | Columbus |
Michigan | Detroit |
<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>
我知道你在想什么 - "我这辈子从来没想过要建一个这样的表格……" - 但请听我说!
¥I know what you're thinking — "I have never in my life wanted to build a table that looks like that..." — but listen for a second!
有一种情况尤其适用:当你构建一个带有固定标题行的表格,并且希望标题下方有一个固定的底部边框时,这个功能会非常有用:
¥One situation where this is actually super useful is when building a table with a sticky header row and you want a persistent bottom border under the headings:
滚动此表格可查看粘性标题行的实际效果
Name | Role | |
---|---|---|
Courtney Henry | courtney.henry@example.com | Admin |
Tom Cook | tom.cook@example.com | Member |
Whitney Francis | whitney.francis@example.com | Admin |
Leonard Krasner | leonard.krasner@example.com | Owner |
Floyd Miles | floyd.miles@example.com | Member |
Emily Selman | emily.selman@example.com | Member |
Kristin Watson | kristin.watson@example.com | Admin |
Emma Dorsey | emma.dorsey@example.com | Member |
Alicia Bell | alicia.bell@example.com | Admin |
Jenny Wilson | jenny.wilson@example.com | Owner |
Anna Roberts | anna.roberts@example.com | Member |
Benjamin Russel | benjamin.russel@example.com | Member |
Jeffrey Webb | jeffrey.webb@example.com | Admin |
Kathryn Murphy | kathryn.murphy@example.com | Member |
<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 很有趣,不是吗?
¥You might think you could just use border-collapse
here since you actually don't want any space between the borders but you'd be mistaken. Without border-separate
and border-spacing-0
, the border will scroll away instead of sticking under the headings. CSS is fun isn't it?
查看 边框间距文档 了解更多详细信息。
¥Check out the border spacing documentation for some more details.
已启用和可选的变体(Enabled and optional variants)
¥Enabled and optional variants
我们为 :enabled
和 :optional
伪类添加了新的变体,当它们处于启用状态且可选状态时,它们会针对表单元素。
¥We've added new variants for the :enabled
and :optional
pseudo-classes, which target form elements when they are, well, enabled and optional.
“但是 Adam,我为什么需要这些?启用和可选甚至不是状态,它们是默认的。”你真的会做网站吗?
¥"But Adam why would I ever need these, enabled and optional aren't even states, they are the defaults. Do you even make websites?"
哎呀,这很伤人,因为这是真的 - 我现在几乎只是在 GitHub 上一遍又一遍地写电子邮件和回答同样的问题。
¥Ouch, that hurts because it's true — I pretty much just write emails and answer the same questions over and over again on GitHub now.
但请看一下这个已禁用按钮的示例:
¥But check out this disabled button example:
<button type="button" class="bg-indigo-500 hover:bg-indigo-400 disabled:opacity-75 ..." disabled>Processing...</button>
注意到当你将鼠标悬停在按钮上时,即使按钮已禁用,背景颜色仍然会改变吗?在此版本发布之前,通常会这样修复这个问题:
¥Notice how when you hover over the button, the background still changes color even though it's disabled? Before this release, you'd usually fix that like this:
<button type="button" class="bg-indigo-500 hover:bg-indigo-400 disabled:opacity-75 disabled:hover:bg-indigo-500 ..." disabled> Processing...</button>
但是,有了新的 enabled
修饰符,你可以像这样写:
¥But with the new enabled
modifier, you can write it like this instead:
<button type="button" class="bg-indigo-500 hover:enabled:bg-indigo-400 disabled:opacity-75 ..." disabled> Processing...</button>
我们结合了 hover
和 enabled
两种变体,在按钮禁用时,无需将悬停颜色覆盖回默认颜色,而是在按钮禁用时直接应用悬停样式。我觉得这样更好!
¥Instead of overriding the hover color back to the default color when the button is disabled, we combine the hover
and enabled
variants to just not apply the hover styles when the button is disabled in the first place. I think that's better!
以下是结合使用新的 optional
修饰符和 兄弟状态功能 修饰符的示例,用于隐藏非必填字段的 "必需" 提示:
¥Here's an example combining the new optional
modifier with our sibling state features to hide a little "Required" notice for fields that aren't required:
<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 为你处理所有条件渲染,而不必自己处理。挺棒的!
¥This lets you use the same markup for all of your form groups and letting CSS handle all of the conditional rendering for you instead of handling it yourself. Kinda neat!
Prefers-contrast 变体(Prefers-contrast variants)
¥Prefers-contrast variants
你知道有 prefers-contrast
媒体查询吗?现在确实有,而且 Tailwind 开箱即用。
¥Did you know there's a prefers-contrast
media query? Well there is, and now Tailwind supports it out of the box.
当用户请求增加或减少对比度时,使用新的 contrast-more
和 contrast-less
变体来修改你的设计,通常是通过操作系统辅助功能首选项(例如 macOS 上的 "增加对比度")来实现。
¥Use the new contrast-more
and contrast-less
variants to modify your design when the user has requested more or less contrast, usually through an operating system accessibility preference like "Increase contrast" on 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>
我为此编写了 一些文档,但说实话,我在这里写的比在那里写的多。
¥I wrote some documentation for this but honestly I wrote more here than I did there.
设置原生对话框背景样式(Style native dialog backdrops)
¥Style native dialog backdrops
如果你喜欢走在前沿,那么相当新的 HTML <dialog>
元素 和出乎意料地优秀的 浏览器支持 绝对值得一试。
¥There's a pretty new HTML <dialog>
element with surprisingly decent browser support that is worth playing with if you like to live on the bleeding edge.
对话框有一个新的 ::backdrop
伪元素,它会在对话框打开时渲染,而 Tailwind CSS v3.1 添加了一个新的 backdrop
修饰符,你可以使用它来设置这个宝贝的样式:
¥Dialogs have this new ::backdrop
pseudo-element that's rendered while the dialog is open, and Tailwind CSS v3.1 adds a new backdrop
modifier you can use to style this baby:
<dialog class="backdrop:bg-slate-900/50 ..."> <form method="dialog"> <!-- ... --> <button value="cancel">Cancel</button> <button>Submit</button> </form></dialog>
如果你想深入了解这件事,我推荐你阅读 MDN 对话框文档 - 它很令人兴奋,但也有很多东西需要了解。
¥I recommend reading the MDN Dialog documentation if you want to dig in to this thing more — it's exciting stuff but there's a lot to know.
变体可设置任意值(Arbitrary values but for variants)
¥Arbitrary values but for variants
好吧,这对我来说是真正的亮点 - 你知道我们是如何为你提供 addVariant
API 来创建你自己的自定义变体的吗?
¥Okay so this one is the real highlight for me — you know how we give you the addVariant
API for creating your own custom variants?
const plugin = require("tailwindcss/plugin");module.exports = { // ... plugins: [ plugin(function ({ addVariant }) { addVariant("third", "&:nth-child(3)"); }), ],};
……你知道我们如何使用 任意值 直接在 HTML 中将任何你想要的值与实用程序一起使用吗?
¥...and you know how we have arbitrary values for using any value you want with a utility directly in your HTML?
<!--] --><div class="top-[117px]"> <!-- ... --></div>
Tailwind CSS v3.1 引入了 任意变体,让你可以直接在 HTML 中创建自己的临时变体:
¥Well Tailwind CSS v3.1 introduces arbitrary variants, letting you create your own ad hoc variants directly in your HTML:
<div class="[&:nth-child(3)]:py-0"> <!-- ... --></div>
这对于需要参数化的变体非常有用,例如,如果浏览器支持使用 @supports
查询的特定 CSS 功能,则添加样式:
¥This is super useful for variants that sort of feel like they need to be parameterized, for example adding a style if the browser supports a specific CSS feature using a @supports
query:
<div class="bg-white [@supports(backdrop-filter:blur(0))]:bg-white/50 [@supports(backdrop-filter:blur(0))]:backdrop-blur"> <!-- ... --></div>
你甚至可以使用此功能将子元素定位到具有任意变体(例如 [&>*]
)的子元素:
¥You can even use this feature to target child elements with arbitrary variants like [&>*]
:
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
:
¥You can even style the first p
inside the div
in the second child li
but only on 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 样式时,它可能是一个非常有用的逃生出口。它是一把锋利的刀,但最好的厨师不会用安全剪刀来准备食物。
¥Now should you do this? Probably not very often, but honestly it can be a pretty useful escape hatch when trying to style HTML you can't directly change. It's a sharp knife, but the best chefs aren't preparing food with safety scissors.
试用一下,我敢打赌,你会发现它们在需要时非常有用。我们正在努力改进,其体验比创建自定义类要好得多。
¥Play with them a bit and I'll bet you find they are a great tool when the situation calls for it. We're using them in a couple of tricky spots in these new website templates we're working on and the experience is much nicer than creating a custom class.
这就是 Tailwind CSS v3.1!这只是一个小版本变更,因此没有重大更改,你只需安装最新版本即可更新你的项目:
¥So that's Tailwind CSS v3.1! It's only a minor version change, so there are no breaking changes and you should be able to update your project by just installing the latest version:
npm install tailwindcss@latest
如需查看完整的更改列表(包括错误修复和一些我在此处未提及的小改进),请深入研究 GitHub 上的 发行说明。
¥For the complete list of changes including bug fixes and a few minor improvements I didn't talk about here, dig in to the release notes on GitHub.
我已经对 Tailwind CSS v3.2 有很多想法(也许最终还会有文本阴影?!),但现在我们正在努力将这些新的 网站模板 推向终点。请在接下来的一两周内关注该主题的其他更新!
¥I've already got a bunch of ideas for Tailwind CSS v3.2 (maybe even text shadows finally?!), but right now we're working hard to push these new website templates over the finish line. Look for another update on that topic in the next week or two!