
Tailwind CSS v3.2 已经发布,带来了大量全新的功能,包括对动态断点的支持、单个项目中的多个配置文件、嵌套组、参数化变体、容器查询等等。
🌐 Tailwind CSS v3.2 is here with an absolutely massive amount of new stuff, including support for dynamic breakpoints, multiple config files in a single project, nested groups, parameterized variants, container queries, and more.
像往常一样,请查看 发行说明了解每一个细节修复和改进,但这里是重点内容概览:
-
Multiple config files in one project using
@config -
基于浏览器支持的样式,使用
supports-* - ARIA 属性变体
- 数据属性变体
- 最大宽度和动态断点
-
动态
group-*和peer-*变体 -
带有
matchVariant的动态变体 -
Nested
groupand multiplepeersupport using variant modifiers - 容器查询
通过从 npm 安装最新版本的 tailwindcss 来升级你的项目:
🌐 Upgrade your projects by installing the latest version of tailwindcss from npm:
npm install -D tailwindcss@latest或者在 Tailwind Play中玩转新功能,你可以直接在浏览器中立即尝试所有内容。
使用 @config 在一个项目中使用多个配置文件(Multiple config files in one project using @config)
我们添加了一个新的 @config 指令,你可以在 CSS 文件中使用它来指定该文件使用哪个 Tailwind CSS 配置:
🌐 We've added a new @config directive that you can use in a CSS file to specify which Tailwind CSS config to use for that file:
@config "./tailwind.admin.config.js";@tailwind base;@tailwind components;@tailwind utilities;这使得在一个项目中构建多个具有独立 Tailwind 配置的样式表变得容易得多。例如,你可能为面向客户的网站部分有一个配置文件,而为管理/后台区域有另一个配置文件。
🌐 This makes it a lot easier to build multiple stylesheets in a single project that have separate Tailwind configurations. For example, you might have one config file for the customer-facing part of your site, and another config for the admin/backend area.
你一直从技术上可以通过足够的 webpack 技巧来做到这一点,但新的 @config 指令让这一切变得非常简单且人人可用,即使是在你无法完全控制构建工具配置的项目中也一样。
🌐 You've always technically been able to do this with enough webpack wizardry, but the new @config directive makes it super easy and accessible to everyone, even in projects where you don't have as much control over the build tool configuration.
基于浏览器支持的样式,使用 supports-*(Browser-support-based styling with supports-*)
现在,你可以根据用户浏览器是否支持某个特性来有条件地设置样式,使用 supports-[...] 变体,它在内部会生成 @supports 规则。
🌐 You can now conditionally style things based on whether a certain feature is supported in the user's browser with the supports-[...] variant, which generates @supports rules under the hood.
<div class="flex supports-[display:grid]:grid ..."> <!-- ... --></div>supports-[...] 变体可以使用你在方括号中用作 @supports (...) 的任何内容,例如属性/值对,甚至可以使用 and 和 or 的表达式。
🌐 The supports-[...] variant takes anything you'd use with @supports (...) between the square brackets, like a property/value pair, and even expressions using and and or.
如果你只需要检查某个属性本身是否受支持,你甚至可以只指定属性名称,Tailwind 会为你填写所有信息:
🌐 If you only need to check if a property itself is supported, you can even just specify the property name and Tailwind will fill in the blanks for you:
<div class="bg-black/75 supports-[backdrop-filter]:bg-black/25 supports-[backdrop-filter]:backdrop-blur ..."> <!-- ... --></div>ARIA 属性变体(ARIA attribute variants)
你现在可以使用新的 aria-* 变体根据 ARIA 属性 有条件地设置样式。
🌐 You can now conditionally style things based on ARIA attributes with the new aria-* variants.
例如,你可以根据 aria-checked 状态是否为 true 来更新元素的背景颜色:
🌐 For example, you can update the background color of an element based on whether the aria-checked state is true:
<span class="bg-gray-600 aria-checked:bg-blue-600" aria-checked="true" role="checkbox"> <!-- ... --></span>默认情况下,我们已为最常用的布尔 ARIA 属性添加了修饰符:
🌐 By default we've included modifiers for the most common boolean ARIA attributes:
| Modifier | CSS |
|---|---|
aria-checked | &[aria-checked="true"] |
aria-disabled | &[aria-disabled="true"] |
aria-expanded | &[aria-expanded="true"] |
aria-hidden | &[aria-hidden="true"] |
aria-pressed | &[aria-pressed="true"] |
aria-readonly | &[aria-readonly="true"] |
aria-required | &[aria-required="true"] |
aria-selected | &[aria-selected="true"] |
你可以通过编辑你的 tailwind.config.js 文件中的 theme.aria 或 theme.extend.aria 来自定义可用的 aria-* 修饰符:
🌐 You can customize which aria-* modifiers are available by editing theme.aria or theme.extend.aria in your
tailwind.config.js file:
module.exports = { theme: { extend: { aria: { asc: 'sort="ascending"', desc: 'sort="descending"', }, }, },};如果你需要使用一次性的 aria 修饰符,而将其包含在主题中没有意义,或者需要更复杂的 ARIA 属性并且这些属性有特定的值,可以使用方括号来即时生成一个使用任意值的属性。
🌐 If you need to use a one-off aria modifier that doesn’t make sense to include in your theme, or for more complex ARIA attributes that take specific values, use square brackets to generate a property on the fly using any arbitrary value.
| Invoice # | Client | Amount |
|---|---|---|
| #100 | Pendant Publishing | $2,000.00 |
| #101 | Kruger Industrial Smoothing | $545.00 |
| #102 | J. Peterman | $10,000.25 |
<table> <thead> <tr> <th aria-sort="ascending" class="aria-[sort=ascending]:bg-[url('/img/down-arrow.svg')] aria-[sort=descending]:bg-[url('/img/up-arrow.svg')]" > Invoice # </th> <!-- ... --> </tr> </thead> <!-- ... --></table>ARIA 状态修饰符也可以使用 group-aria-* 和 peer-aria-* 修饰符来定位父元素和兄弟元素:
🌐 ARIA state modifiers can also target parent and sibling elements using the group-aria-* and peer-aria-* modifiers:
<table> <thead> <tr> <th aria-sort="ascending" class="group"> Invoice # <svg class="group-aria-[sort=ascending]:rotate-0 group-aria-[sort=descending]:rotate-180" > <!-- ... --> </svg> </th> <!-- ... --> </tr> </thead> <!-- ... --></table>数据属性变体(Data attribute variants)
你现在可以使用新的 data-* 变体根据 数据属性 有条件地设置样式。
🌐 You can now conditionally style things based on data attributes with the new data-* variants.
由于按定义没有标准的 data-* 属性,我们仅支持任意值,例如:
🌐 Since there are no standard data-* attributes by definition, we only support arbitrary values out of the box, for example:
<!-- Will apply --><div data-size="large" class="data-[size=large]:p-8"> <!-- ... --></div><!-- Will not apply --><div data-size="medium" class="data-[size=large]:p-8"> <!-- ... --></div><!-- Generated CSS --><style> .data-\[size\=large\]\:p-8[data-size="large"] { padding: 2rem; }</style>你可以在 tailwind.config.js 文件的 theme 部分的 data 键下,为项目中常用的数据属性选择器配置快捷方式:
🌐 You can configure shortcuts for common data attribute selectors you're using in your project under the data key in the theme section of your tailwind.config.js file:
// tailwind.config.jsmodule.exports = { theme: { data: { checked: 'ui~="checked"', }, }, // ...};<div data-ui="checked active" class="data-checked:underline"> <!-- ... --></div>这些变体也可以作为 group-* 和 peer-* 变体使用,就像框架中的许多其他变体一样:
🌐 These variants also work as group-* and peer-* variants like many other variants in the framework:
<div data-size="large" class="group"> <div class="group-data-[size=large]:p-8"> <!-- Will apply `p-8` --> </div></div><div data-size="medium" class="group"> <div class="group-data-[size=large]:p-8"> <!-- Will not apply `p-8` --> </div></div>最大宽度和动态断点(Max-width and dynamic breakpoints)
我们新增了一个 max-* 变体,让你可以根据已配置的断点应用最大宽度的媒体查询:
🌐 We've added a new max-* variant that lets you apply max-width media queries based on your configured breakpoints:
<div class="max-lg:p-8"> <!-- Will apply `p-8` until the `lg` breakpoint kicks in --></div>一般来说,我个人仍然建议使用最小宽度断点,但这个功能确实带来了一个有用的工作流程好处,那就是不必在不同的断点上去 撤销 某些样式。
🌐 As a general rule I would still recommend using min-width breakpoints personally, but this feature does unlock one useful workflow benefit which is not having to undo some style at a different breakpoint.
例如,如果没有此功能,你通常会执行以下操作:
🌐 For example, without this feature you often end up doing things like this:
<div class="md:sr-only xl:not-sr-only"> <!-- ... --></div>通过此功能,你可以通过在原始声明上叠加 max-* 变体来避免撤销该样式:
🌐 With this feature, you can avoid undoing that style by stacking a max-* variant on the original declaration:
<div class="md:max-xl:sr-only"> <!-- ... --></div>与此同时,我们增加了对任意值的支持,以及一个新的 min-* 变体,它只接受任意值,所以你可以像这样操作:
🌐 Along with this, we've added support for arbitrary values, and a new min-* variant that only accepts arbitrary values, so you can do things like this:
<div class="min-[712px]:max-[877px]:right-16 ..."> <!-- ... --></div>请注意,这些功能只有在你的项目使用简单的 screens 配置时才能使用。
🌐 It's important to note that these features will only be available if your project uses a simple screens configuration.
这些功能比看起来要复杂得多,因为需要确保所有这些媒体查询在最终的 CSS 中的排序方式能够在浏览器中实现你预期的行为。所以目前,它们只有在你的 screens 配置是一个简单的、具有字符串值的对象时才能工作,就像默认配置一样:
🌐 These features are a lot more complicated than they look due to needing to ensure that all of these media queries are sorted in the final CSS in a way that gives you the expected behavior in the browser. So for now, they will only work if your screens configuration is a simple object with string values, like the default configuration:
// tailwind.config.jsmodule.exports = { theme: { screens: { sm: "640px", md: "768px", lg: "1024px", xl: "1280px", "2xl": "1536px", }, },};如果你有一个复杂的配置,其中已经定义了 max-width 断点,或者基于范围的媒体查询,或者除了字符串以外的任何内容,这些功能将无法使用。我们将来可能可以解决这个问题,但这会引发许多关于 CSS 应该如何排序的问题,而我们目前还没有答案。
🌐 If you have a complex configuration where you already have max-width breakpoints defined, or range-based media queries, or anything other than just strings, these features won't be available. We might be able to figure that out in the future but it just creates so many questions about how the CSS should be ordered that we don't have answers for yet.
所以目前(也可能是永久),如果你想使用这些功能,你的 screens 配置需要保持简单。我希望这些功能无论如何都能让复杂的 screens 配置变得不必要。
🌐 So for now (and possibly forever), if you want to use these features, your screens configuration needs to be simple. My hope is that these features make complex screens configurations unnecessary anyways.
动态组-* 和对等-* 变体(Dynamic group-* and peer-* variants)
现在可以通过传入你自己的选择器来即时创建自定义的 group-* 和 peer-* 变体,这些选择器会在方括号内被“分组化”或“同伴化”:
🌐 It's now possible to create custom group-* and peer-* variants on the fly by passing your own selector to be "groupified" or "peerified" between square brackets:
<div class="group is-published"> <div class="group-[.is-published]:block hidden">Published</div></div>为了获得更多控制,你可以使用 & 字符来标记 .group 或 .peer 应该在最终选择器中相对于你传入的选择器的位置:
🌐 For more control, you can use the & character to mark where .group or .peer should end up in the final selector relative to the selector you are passing in:
<div> <input type="text" class="peer" /> <div class="peer-[:nth-of-type(3)_&]:block hidden"> <!-- ... --> </div></div>说实话,你可能一生中只会用这些功能三次,但它仍然很酷。希望我们能以此为基础,让 group 和 peer 将来能更自动地与第三方插件注册的变体一起工作。
🌐 Let's be serious you're probably going to use these features like three times in your entire life but it's still pretty cool. Hoping we can use this as a building block to make group and peer work more automatically with variants registered by third-party plugins in the future.
使用 matchVariant 的动态变体(Dynamic variants with matchVariant)
你可能已经注意到在许多新功能中出现了这种新的 variant-[...] 语法——这都是由一个新的 matchVariant 插件 API 提供支持,它使得创建我们所谓的“动态变体”成为可能。
🌐 You've probably noticed this new variant-[...] syntax in a lot of these new features — this is all powered by a new matchVariant plugin API that makes it possible to create what we're calling "dynamic variants".
这是一个为某个虚拟提示工具库创建 placement-* 变体的示例,该库使用 data-placement 属性来告诉你提示当前的位置:
🌐 Here's an example of creating a placement-* variant for some imaginary tooltip library that uses a data-placement attribute to tell you where the tooltip is currently positioned:
let plugin = require("tailwindcss/plugin");module.exports = { // ... plugins: [ plugin(function ({ matchVariant }) { matchVariant( "placement", (value) => { return `&[data-placement=${value}]`; }, { values: { t: "top", r: "right", b: "bottom", l: "left", }, }, ); }), ],};上面定义的变体会给你类似 placement-t 和 placement-b 的变体,但也会支持方括号中的任意部分,所以如果这个假想的工具提示库有其他可能的值,而你又觉得不需要为其创建内置值,你仍然可以这样操作:
🌐 The variant defined above would give you variants like placement-t and placement-b, but would also support the arbitrary portion in square brackets, so if this imaginary tooltip library had other potential values that you didn't feel the need to create built-in values for, you could still do stuff like this:
<div class="placement-[top-start]:mb-2 ..."> <!-- ... --></div>在使用此 API 定义自定义变体时,通常重要的是你能够控制 CSS 的生成顺序,以确保每个类相对于来自同一变体的其他值具有正确的优先级。为支持这一点,在定义变体时你可以提供一个 sort 函数:
🌐 When defining a custom variant with this API, it's often important that you have some control over which order the CSS is generated in to make sure each class has the right precedence with respect to other values that come from the same variant. To support this, there's a sort function you can provide when defining your variant:
matchVariant("min", (value) => `@media (min-width: ${value})`, { sort(a, z) { return parseInt(a) - parseInt(z); },});使用变体修饰符支持嵌套组和多个同级元素(Nested group and multiple peer support using variant modifiers)
当你在彼此嵌套的多个 group 块中工作时,有时可能会遇到问题,因为 Tailwind 没有真正的方法来区分它们。
🌐 Sometimes you can run into problems when you have multiple group chunks nested within each other because Tailwind has no real way to disambiguate between them.
为了解决这个问题,我们正在增加对 variant 修饰符 的支持,它是一种新的动态部分,你可以将它添加到变体的末尾(灵感来自我们可选的不透明度修饰符语法),用来为每个组/同伴提供你自己的标识符。
🌐 To solve this, we're adding support for variant modifiers, which are a new dynamic chunk that you can add to the end of a variant (inspired by our optional opacity modifier syntax) that you can use to give each group/peer your own identifier.
它的样子如下:
🌐 Here's what it looks like:
<div class="group/sidebar ..."> <!-- ... --> <div class="group/navitem ..."> <a href="#" class="opacity-50 group-hover/navitem:bg-black/75 group-hover/sidebar:opacity-75"> <!-- ... --> </a> </div> <!-- ... --></div>这让你可以为每个组指定一个清晰的名称,使其在运行时与上下文相符,Tailwind 将生成必要的 CSS 使其正常工作。
🌐 This lets you give each group a clear name that makes sense for that context on the fly, and Tailwind will generate the necessary CSS to make it work.
我非常高兴能有解决方案,因为多年来我一直在努力寻找一个好的方法来解决它,而这是我们想到的第一个真正提供我认为它应该具备的强大功能和灵活性的解决方案。
🌐 I'm really excited to have a solution out there for this because it's something I've been trying to land on a good approach for solving for several years, and this is the first thing we've come up with that really feels like it offers the power and flexibility I think it should.
容器查询(Container queries)
我几乎不敢相信,容器查询 终于成为现实,而且浏览器支持已经接近可以在生产环境中使用的程度 —— 事实上,如果你正在开发 Electron 应用,你今天就可以使用它们。
🌐 I can barely believe it but container queries are finally real and the browser support is dangerously close to making these ready for production — in fact if you're building an Electron app you could use these today.
今天我们发布了 @tailwindcss/container-queries,这是一个新的官方插件,它为框架添加了容器查询支持,使用新的 @ 语法将其与普通媒体查询区分开来:
🌐 Today we're releasing @tailwindcss/container-queries which is a new first-party plugin that adds container query support to the framework, using a new @ syntax to differentiate them from normal media queries:
<div class="@container"> <div class="block @lg:flex"> <!-- ... --> </div></div>我们开箱即用地提供了一套与默认 max-width 尺寸匹配的容器规范:
🌐 Out-of-the-box we include a set of container sizes that match our default max-width scale:
| 名称 | 值 |
|---|---|
| xs | 20rem |
| sm | 24rem |
| md | 28rem |
| lg | 32rem |
| xl | 36rem |
| 2xl | 42rem |
| 3xl | 48rem |
| 4xl | 56rem |
| 5xl | 64rem |
| 6xl | 72rem |
| 7xl | 80rem |
你可以使用 tailwind.config.js 文件中的 containers 键来配置可用的值:
🌐 You can configure which values are available using the containers key in your tailwind.config.js file:
// tailwind.config.jsmodule.exports = { theme: { extend: { containers: { "2xs": "16rem", // etc... }, }, },};我们还支持使用 @[...] 语法的任意值:
🌐 We also include support for arbitrary values, using the @[...] syntax:
<div class="@container"> <div class="block @[618px]:flex"> <!-- ... --> </div></div>...并使用相同的变体修饰符语法为容器命名,这正是我们现在为 group-* 和 peer-* 变体提供的语法:
<div class="@container/main"> <!-- ... --> <div> <div class="block @lg/main:flex"> <!-- ... --> </div> </div></div>目前我们从简单的基于 min-width 的容器查询开始,但我们计划随着时间推移扩大范围,当我们觉得已经真正掌握了这些 API 时,我们会将其全部纳入核心。
🌐 Right now we're starting with simple min-width based container queries, but we plan to expand the scope over time, and when it feels like we've really nailed the APIs we'll bring it all into core.
有关完整文档,请查看 GitHub 上的插件。
所以,这就是 Tailwind CSS v3.2!有了重大的改进,但只是一个小版本更新,所以没有破坏性更改,你只需更新依赖就可以更新你的项目:
🌐 So there you have it — Tailwind CSS v3.2! Major improvements but just a minor version change, so no breaking changes and you should be able to update your project by just updating your dependency:
npm install -D tailwindcss@latest是啊,我听到你在后台说的,文本阴影仍然没有,但嘿,至少你可以在不离开 HTML 的情况下,当复选框的父元素是列表中的第三个子元素时,给复选框的兄弟元素设置样式。大家要知道优先顺序。
🌐 Yeah I hear you in the back, still no text shadows, but hey at least you can style the sibling of a checkbox when the checkbox's parent is the third child in a list without leaving your HTML. Priorities people.