Tailwind CSS v3.4:动态视口单位、:has() 支持、平衡标题、子网格等

Adam Wathan
Tailwind CSS v3.4

没有什么比构建 一款重要的新产品 更能让你找到所有你希望在自己的工具中拥有的功能了,所以我们汲取了一些灵感,将其转化为 Tailwind CSS v3.4。

¥There's nothing like building a major new product for finding all the features you wish you had in your own tools, so we capitalized on some of that inspiration and turned it into this — Tailwind CSS v3.4.

一如既往,改进范围广泛,从多年来让你感到不满的方面,到支持你从未听说过、甚至可能在工作中用不到的 CSS 功能。

¥As always the improvements range from things you've been angry about for years, to supporting CSS features you've never even heard of and probably can't even use at work.

所有好东西都包含在该列表中,但请查看 发行说明 了解更多细节,它们可能不够精彩,不足以在这篇文章中提及。

¥All the good stuff is in that list, but check out the release notes for a couple more details that weren't exciting enough to earn a spot in this post.

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

¥Upgrade your projects by installing the latest version of tailwindcss from npm:

npm install tailwindcss@latest

或者,直接在浏览器中试用 Tailwind Play 的所有新功能。

¥Or try out all of the new features on Tailwind Play, right in your browser.


动态视口单位(Dynamic viewport units)

¥Dynamic viewport units

vh 单元添加到浏览器中时,我们都非常兴奋 - 终于可以构建全高应用布局和其他内容,而无需在 17 层 DOM 层中钻研 height: 100% 了!但移动设备及其该死的消失菜单栏破坏了所有的乐趣,实际上使 vh 单元成为一个残酷的提醒,提醒我们一个本可以如此美好的未来。

¥When the vh unit was added to browsers we all got so excited — finally a way to build full-height application layouts and stuff without drilling height: 100% through 17 layers of DOM! But mobile devices and their damn disappearing menu bars spoiled all the fun, effectively making the vh unit just a cruel reminder of a future that could've been so great.

现在,我们迎来了新的未来 - dvhlvhsvh 的设计旨在适应即将消失的浏览器边框,而 Tailwind CSS v3.4 开箱即用地支持它们:

¥Well we've got a new future now — dvh, lvh, and svh are designed to accommodate that disappearing browser chrome and Tailwind CSS v3.4 supports them out of the box:

在视口中上下滚动可隐藏/显示浏览器 UI

tailwindcss.com

h-dvh

<div class="h-dvh">
<!-- ... -->
</div>

我们默认添加了以下新类:

¥We've added the following new classes by default:

CSS
h-svhheight: 100svh
h-lvhheight: 100lvh
h-dvhheight: 100dvh
min-h-svhmin-height: 100svh
min-h-lvhmin-height: 100lvh
min-h-dvhmin-height: 100dvh
max-h-svhmax-height: 100svh
max-h-lvhmax-height: 100lvh
max-h-dvhmax-height: 100dvh

如果你需要其他值,你也可以像 min-h-[75dvh] 一样使用任意值。

¥If you need other values, you can always use arbitrary values too like min-h-[75dvh].

目前浏览器对这些功能的支持度为 非常棒,因此除非你需要支持 Safari 14,否则你可以立即开始使用它们。

¥Browser support is pretty great for these nowadays, so unless you need to support Safari 14 you can start using these right away.


新的 :has() 变体(New :has() variant)

¥New :has() variant

:has() 伪类 是自 flexbox 以来 CSS 中添加的最强大的功能。有史以来第一次,你可以基于子元素(而非父元素)来设置元素的样式。它甚至可以根据后续兄弟元素设置样式。

¥The :has() pseudo-class is the most powerful thing that's been added to CSS since flexbox. For the first time ever, you can style an element based on its children, not just based on its parents. It even makes it possible to style based on subsequent siblings.

以下是示例,如果父级组件中的单选按钮被选中,则父级组件会显示一个彩色环:

¥Here's an example where the parent gets a colored ring if the radio button inside of it is checked:

Payment method
<label class="has-[:checked]:bg-indigo-50 has-[:checked]:text-indigo-900 has-[:checked]:ring-indigo-500 ...">
<svg fill="currentColor">
<!-- ... -->
</svg>
Google Pay
<input type="radio" class="accent-indigo-500 ..." />
</label>

在过去几个月开发新的 UI 工具包的过程中,我感觉每周都能发现 :has() 的一个新用例,它取代了我们代码中大量的 JavaScript。

¥I feel like I've found a new use-case for :has() every week while working on this new UI kit we've been building for the last few months, and it's replaced a crazy amount of JavaScript in our code.

例如,我们的文本输入在设计上相当复杂,需要一些封装器元素来构建。如果没有 :has(),我们无法根据输入的 :disabled 状态等信息来设置封装器的样式,但现在我们可以:

¥For example, our text inputs are pretty complicated design-wise and require a little wrapper element to build. Without :has(), we had no way of styling the wrapper based on things like the :disabled state of the input, but now we can:

input.jsx
export function Input({ ... }) {
return (
<span className="has-[:disabled]:opacity-50 ...">
<input ... />
</span>
)
}

这个语法相当前沿,但从今天起,所有主流浏览器的最新版本都支持它。给所有 Firefox 用户几周时间来安装今天的更新,我们应该可以尽情使用了。

¥This one is pretty bleeding edge but as of literally today it's now supported in the latest version of all major browsers. Give it a few weeks for any Firefox users to install today's update and we should be able to go wild with it.


使用 * 变体设置子元素样式(Style children with the * variant)

¥Style children with the * variant

这是人们一直以来梦寐以求的 — 一种使用实用程序类来为父级组件设置子级样式的方法。

¥Here's one people have wanted for literally ever — a way to style children from the parent using utility classes.

我们添加了一个新的 * 变体,针对直接子级,可让你执行以下操作:

¥We've added a new * variant that targets direct children, letting you do stuff like this:

Categories

Sales
Marketing
SEO
Analytics
Design
Strategy
Security
Growth
Mobile
UX/UI
<div>
<h2>Categories:<h2>
<ul class="*:rounded-full *:border *:border-sky-100 *:bg-sky-50 *:px-2 *:py-0.5 dark:text-sky-300 dark:*:border-sky-500/15 dark:*:bg-sky-500/10 ...">
<li>Sales</li>
<li>Marketing</li>
<li>SEO</li>
<!-- ... -->
</ul>
</div>

一般来说,我建议直接为子元素设置样式,但当你无法控制这些元素,或者需要根据元素所处的上下文进行条件调整时,这种方法会很有用。

¥Generally I'd recommend just styling the children directly, but this can be useful when you don't control those elements or need to make a conditional tweak because of the context the element is used in.

它还可以与其他变体组合使用,例如,当子元素悬停时,hover:*:underline 会为其设置样式。

¥It can be composed with other variants too, for instance hover:*:underline will style any child when the child is hovered.

以下是我们正在进行的一种很酷的工作方式:

¥Here's a cool way we're using that to conditionally add layout styles to different child elements in the new UI kit we're working on:

JSX
function Field({ children }) {
return (
<div className="data-[slot=description]:*:mt-4 ...">
{children}
</div>
)
}
function Description({ children }) {
return (
<p data-slot="description" ...>{children}</p>
)
}
function Example() {
return (
<Field>
<Label>First name</Label>
<Input />
<Description>Please tell me you know your own name.</Description>
</Field>
)
}

看到那个疯狂的 data-[slot=description]:*:mt-4 类了吗?它首先定位所有直接子元素(即 *: 部分),然后使用 data-[slot=description] 将它们过滤到仅具有 data-slot="description" 属性的项目。

¥See that crazy data-[slot=description]:*:mt-4 class? It first targets all direct children (that's the *: part), then filters them down to just items with a data-slot="description" attribute using data-[slot=description].

这样可以轻松地只针对特定的子元素,而无需一路下降到原始的任意变体。

¥This makes it easy to target only specific children, without having to drop all the way down to a raw arbitrary variant.

期待看到大家做的那些让我后悔添加这个功能的糟糕事情。

¥Looking forward to seeing all the horrible stuff everyone does to make me regret adding this feature.


新的 size-* 实用程序(New size-* utilities)

¥New size-* utilities

你厌倦了每次需要调整头像大小时都输入 h-5 w-5,你和我都了解这一点。

¥You're sick of typing h-5 w-5 every time you need to size an avatar, you know it and I know it.

在 Tailwind CSS v3.4 中,我们终于添加了一个新的 size-* 实用程序,可以同时设置宽度和高度:

¥In Tailwind CSS v3.4 we've finally added a new size-* utility that sets width and height at the same time:

HTML
<div>
<img class="h-10 w-10" ...>
<img class="h-12 w-12" ...>
<img class="h-14 w-14" ...>
<img class="size-10" ...>
<img class="size-12" ...>
<img class="size-14" ...>
</div>

我们一直想添加这个功能,但一直纠结于确切的名称 - 与 w-*h-* 相比,size-* 的输入量太大,而 s-* 又太过神秘。

¥We've wanted to add this forever but have always been hung up on the exact name — size-* felt like so much to type compared to w-* or h-* and s-* felt way too cryptic.

使用了几周后,我可以肯定地说,即使名字更长,它也比单独的宽度和高度实用程序好得多。超级方便,尤其是在将其与变体结合使用或使用复杂的任意值时。

¥After using it for a few weeks though I can say decisively that even with the longer name, it's way better than separate width and height utilities. Super convenient, especially if you're combining it with variants or using a complex arbitrary value.


使用 text-wrap 实用程序平衡标题(Balanced headlines with text-wrap utilities)

¥Balanced headlines with text-wrap utilities

你花了多少时间摆弄 max-width 或插入响应式换行符,试图让那些小标题在你的落地页上整齐地换行?现在你无需再为此花费时间,因为浏览器可以通过 text-wrap: balance 为你完成:

¥How much time have you spent fiddling with max-width or inserting responsive line breaks to try and make those little section headings wrap nicely on your landing pages? Well now you can spend zero time on it, because the browser can do it for you with text-wrap: balance:

Beloved Manhattan soup stand closes

New Yorkers are facing the winter chill with less warmth this year as the city's most revered soup stand unexpectedly shutters, following a series of events that have left the community puzzled.

<article>
<h3 class="text-balance ...">Beloved Manhattan soup stand closes<h3>
<p>New Yorkers are facing the winter chill...</p>
</article>

我们还添加了 text-pretty,它尝试使用 text-wrap: pretty 避免段落末尾出现孤立单词:

¥We've also added text-pretty which tries to avoid orphaned words at the end of paragraphs using text-wrap: pretty:

Beloved Manhattan soup stand closes

New Yorkers are facing the winter chill with less warmth this year as the city's most revered soup stand unexpectedly shutters, following a series of events that have left the community puzzled.

<article class="text-pretty ...">
<h3>Beloved Manhattan soup stand closes<h3>
<p>New Yorkers are facing the winter chill...</p>
</article>

这些功能的优点在于,即使有人使用旧版浏览器访问你的网站,他们也会回退到常规的换行行为,因此现在开​​始使用这些功能是完全安全的。

¥The nice thing about these features is that even if someone visits your site with an older browser, they'll just fallback to the regular wrapping behavior so it's totally safe to start using these today.


子网格支持(Subgrid support)

¥Subgrid support

子网格 (Subgrid) 是一项较新的 CSS 功能,它允许元素从其父元素继承网格的列或行,从而可以将其子元素放置在父网格中。

¥Subgrid is a fairly recent CSS feature that lets an element sort of inherit the grid columns or rows from its parent, make it possible to place its child elements in the parent grid.

HTML
<div class="grid grid-cols-4 gap-4">
<!-- ... -->
<div class="col-span-3 grid grid-cols-subgrid gap-4">
<div class="col-start-2">06</div>
</div>
<!-- ... -->
</div>

例如,我们正在 下拉菜单 中改进,这样如果任何项目有图标,所有其他项目都会缩进以保持文本对齐:

¥We're using subgrid in the new UI kit we're working on for example in dropdown menus, so that if any item has an icon, all of the other items are indented to keep the text aligned:

HTML
<div role="menu" class="grid grid-cols-[auto_1fr]">
<a href="#" class="col-span-2 grid-cols-subgrid">
<svg class="mr-2">...</svg>
<span class="col-start-2">Account</span>
</a>
<a href="#" class="col-span-2 grid-cols-subgrid">
<svg class="mr-2">...</svg>
<span class="col-start-2">Settings</span>
</a>
<a href="#" class="col-span-2 grid-cols-subgrid">
<span class="col-start-2">Sign out</span>
</a>
</div>

当所有项目都没有图标时,第一列会缩小到 0px,并且文本会完全左对齐。

¥When none of the items have an icon, the first column shrinks to 0px and the text is aligned all the way to left.

查看 子网格 MDN 文档 了解完整入门指南 - 这个功能一开始可能有点难以理解,但一旦理解,它就会改变游戏规则。

¥Check out the MDN documentation on subgrid for a full primer — it's a bit of a tricky feature to wrap your head around at first, but once it clicks it's a game-changer.


扩展的最小宽度最大宽度和最小高度缩放比例(Extended min-width, max-width, and min-height scales)

¥Extended min-width, max-width, and min-height scales

我们终于扩展了 min-widthmax-widthmin-height 的量表,使其涵盖完整的间距量表,因此像 min-w-12 这样的类现在已经成为现实:

¥We've finally extended the min-width, max-width, and min-height scales to include the full spacing scale, so classes like min-w-12 are actually a real thing now:

HTML
<div class="min-w-12">
<!-- ... -->
</div>

我们应该在 v3.0 中就这么做,但一直没时间 - 很抱歉,不客气。

¥We should've just done this for v3.0 but never really got around to it — I'm sorry and you're welcome.


扩展的不透明度缩放比例(Extended opacity scale)

¥Extended opacity scale

我们还扩展了不透明度比例,使其包含开箱即用的 5 个步骤:

¥We've also extended the opacity scale to include every step of 5 out of the box:

HTML
<div class="opacity-35">
<!-- ... -->
</div>

希望这意味着你的标记中可以少一些随意的值。接下来的 2.5%我会来找你。

¥Hopefully that means a few less arbitrary values in your markup. I'm coming for you next 2.5%.


扩展的 grid-rows-* 缩放比例(Extended grid-rows-* scale)

¥Extended grid-rows-* scale

我们还将内置的网格行数从 6 行增加到 12 行,原因如下:

¥We've also bumped the baked-in number of grid rows from 6 to 12 because why not:

HTML
<div class="grid grid-rows-9">
<!-- ... -->
</div>

也许我们会更疯狂,在下一个版本中将其增加到 16 个字节。

¥Maybe we'll get even crazier and bump it to 16 in the next release.


新的 forced-colors 变体(New forced-colors variant)

¥New forced-colors variant

听说过 强制颜色模式 吗?你的网站在这样的框架下可能看起来很糟糕。

¥Ever heard of forced colors mode? Your site probably looks pretty bad in it.

现在你至少不能责怪我们了,因为 Tailwind CSS v3.4 包含一个 forced-colors 变体,可用于调整强制颜色模式的样式:

¥Well now you can't blame us at least, because Tailwind CSS v3.4 includes a forced-colors variant for adjusting styles for forced colors mode:

HTML
<form>
<input type="checkbox" class="appearance-none forced-colors:appearance-auto ..." />
</form>

它对于微调完全自定义的控件非常有用,尤其是结合任意值和 CSS 系统颜色 的应用知识时。

¥It's really useful for fine-tuning totally custom controls, especially combined with arbitrary values and a working knowledge of CSS system colors.


新的 forced-color-adjust 实用程序(New forced-color-adjust utilities)

¥New forced-color-adjust utilities

我们还添加了新的 forced-color-adjust-autoforces-color-adjust-none 实用程序,用于控制强制颜色模式如何影响你的设计:

¥We've also added new forced-color-adjust-auto and forces-color-adjust-none utilities to control how forced colors mode affects your design:

HTML
<fieldset>
<legend>Choose a color</legend>
<div class="forced-color-adjust-none ...">
<label>
<input class="sr-only" type="radio" name="color-choice" value="white" />
<span class="sr-only">White</span>
<span class="size-6 rounded-full bg-white"></span>
</label>
<label>
<input class="sr-only" type="radio" name="color-choice" value="gray" />
<span class="sr-only">Gray</span>
<span class="size-6 rounded-full bg-gray-300"></span>
</label>
<!-- ... -->
</div>
</fieldset>

这些应该谨慎使用,但当无论如何都必须以特定颜色呈现某些内容时,它们会非常有用,例如,选择某人在网上商店购买的商品的颜色。

¥These should be used pretty sparingly, but they can be useful when it's critical that something is rendered in a specific color no matter what, like choosing the color of something someone is buying in an online store.

要了解有关强制颜色的更多信息,我建议你阅读 Polypane 博客上的 “强制颜色解释:实用指南” - 这是迄今为止我发现的关于这个主题最有用的文章。

¥To learn more about all this forced colors stuff, I recommend reading "Forced colors explained: A practical guide" on the Polypane blog — by far the most useful post I've found on this topic.


如果你一直密切关注,你可能对 Oxide 感到好奇,这是我们今年夏天在 Tailwind Connect 上预览的引擎改进。

¥If you've been paying close attention, you might be wondering about Oxide, the engine improvements we previewed at Tailwind Connect this summer.

我们最初计划在 v3.4 版本中实现这些改进,但还有一些问题需要解决,而且许多其他改进也已经陆续推出,因此我们觉得应该尽快推出,而不是拖延。Oxide 功能仍在开发中,它将成为新年 Tailwind CSS 版本的主要改进。

¥We'd originally slated those improvements for v3.4, but we have a few things still to iron out and so many of these other improvements had been piling up that we felt it made sense to get it all out the door instead of holding it back. The Oxide stuff is still coming, and will be the headlining improvement for the next Tailwind CSS release in the new year.

同时,请使用 npm 更新到最新版本,深入了解 Tailwind CSS v3.4:

¥In the mean time, dig in to Tailwind CSS v3.4 by updating to the latest version with npm:

$ npm install tailwindcss@latest

借助 :has() 和新的 * 变体,你的 HTML 将变得比以往任何时候都更加难以掌控。

¥With :has() and the new * variant, your HTML is about to get more out of control than ever.

TailwindCSS v4.1 中文网 - 粤ICP备13048890号