【译】TailwindCSS vs. UnoCSS

avatar
前端工程师 @木狐

原文# TailwindCSS vs. UnoCSS 由幕呈翻译

关键字: #tailwindcss     #css    #unocss    #web

我是一个TailwindCSS 长期用户, 也是一个实用css的忠实粉丝。很少感到有强烈的转换需求, 但是UnoCSS已经在脑海中浮现了一段时间, 我开始正确的使用它, 所以我认为很有必要写一下我对两者的看法。

这篇文章包含了一些在其他人看来并不是很关注很细小的东西, 但是对于我来说, 越小减少两者的差别越好。

特征

Tailwind具有几乎所有你能想到的所有CSS功能的类名,甚至包括一些你可能不知道的有用功能,像是isolation 。这样的属性即使对于缺少的东西,具有任意值、变体和属性,大多数应用程序也可以在没有自定义 CSS文件或插件的情况下从头到脚设置样式。

Uno支持所有的Tailwind属性,包括一些我欣赏的盒子外放的功能, 例如:变体组、带有CSS网格的流体列,以及更多的动画。

Uno 也有一个可选的“attributify”转换,但我个人更喜欢我的类名保留在与 props 分开的单个属性中。这是个好主意。

语言

Tailwind 对类名有一个定义良好的语言:

  • 每种风格都是一个 kebab-case 大小写的名称,例如 bg-blue-500 , p-4
  • 类也可以使用变体作为类的前缀,例如 md-,hover:
  • 在具体的上下文中,[方括号]中的内容是任意的,可能会根据不同情境有着明确的区别和差异。

这里本身没有规范, 但是我发现他们是一个“可猜测”的系统, 根据它们类名的工作方式, 你可以使用grid-cols-[4rem,1fr,auto]之类的内容,它就可以正常工作。

两者比对,Uno 的默认预设完全基于正则表达式。并没有真正的“语言”存在,也没有标准化,例如 m4 和 m-4 都会产生相同的效果。

这点没有什么实际意义,因为人们实际上仅是把Tailwind 的语言与 Uno 一起使用。Uno可能更适合作为一个框架来,在它之上实现你自己的语言。无论如何,这是我的评估,如果我正在查看它以及它的默认预设作为用于样式化应用程序的用户空间工具。

文档

这两个站点的文档都写的很好,很有用,但是我还是给一个Uno文档一个特别的夸赞,它强调色的转换非常棒。我可能会借鉴一下这个创意,嘿嘿。

自定义样式

这里有一个Tailwind自定义插件的案例:

// adds s-* utilities to apply both width and height
plugin(function size(api) {
  api.matchUtilities(
    { s: (value) => ({ width: value, height: value }) },
    { values: api.theme("width") },
  )
})

下面这个是Uno的案例:

// `s-*` classes to set width and height
[
  /^s-(\d+)$/,
  ([, size]) => ({
    width: `${Number(size) / 4}rem`,
    height: `${Number(size) / 4}rem`,
  }),
  { autocomplete: "s-<num>" },
]

以上两种插件,都可以实现在class上书写s-4转换为width: 1rem; height: 1rem

近年来,Tailwind CSS 的插件 API 已经得到了改进,使得添加简单实用的工具变得更加容易。即使像你提到的这个例子中那样需要更复杂的实用程序,也能够很好地实现。

Uno使用大量正则表达式来实现动态实用程序,看起来感觉很容易出错。Uno鼓励自定义可以接受赋予它的任何值的实用程序,这减少了对 [] 任意值语法的需求。但我仍然更喜欢 Tailwind如何将您限制在一组特定的值中。

另外,Tailwind 的任意值语法也允许使用任何值。但是文档以及使用它所需要的语法都会对其使用进行限制。我喜欢明确、强制执行的标识,即"这不在设计系统中存在"。 相比之下,Uno 或多或少鼓励用户使用他们想要的任何值。虽然在 Uno 中你可以在技术上构建一个更受限制的设计系统,但这需要更多的工作,比起使用 Tailwind 来说需要更多的努力。

编辑器支持

Tailwind的编辑器支持更好一些, 但是还是有一些缺陷存在:

  • 不能识别 CSS 文件中的自定义类名。
  • 在 CSS 中使用 @apply 时,它会自动补全类名,但是在HTML中无法自动补全来自CSS的自定义类名。
  • 在插件中使用 @apply 时,不会自动补全类名。
  • 要获得其他补全上下文,需要配置一个"实验性"选项,并且需要查找问题和讨论才能找到你想要的配置方法。而且,并不是所有情况下都有效,因为...你懂的,正则表达式。

这些问题使得通过 @apply 或在 JavaScript 中使用类名字符串来重用样式变得繁琐。

Tailwind 的作者建议完全不要使用 @apply,但我仍然发现在小的原子元素(如按钮、输入框和链接)中它很有用。

Uno在任何地方都会突出显示类名并给出颜色提示,这对于在独立的字符串中共享类名非常方便。但是,在const transition = useTransition()中看到它突出显示“transition”确实有些滑稽。

此外,Uno的编辑器支持也适用于uno.config.ts,这对于添加自定义的重用类名非常方便。

需要注意的是,在配置文件的顶部添加// @unocss-include才能使其在其中完成类名。这在Remix和PostCSS中很好地工作,但在其他设置中可能会出现问题。老实说,插件应该原生支持这一点。

然而,Uno的自动完成有时会有些棘手:

  • 通常在输入完整的实用程序并输入“-”之前,不会出现自动完成选项。
  • 快捷方式并不总是自动完成,而且不太清楚为什么。
  • 在变体组内部,例如hover:(|),除非在其中加入一个空格,否则自动完成不起作用,如hover:(| )。

总体而言,我发现Uno的编辑器体验比Tailwind更流畅。

Tailwind和Uno各有优势和劣势。我非常赞赏Tailwind的限制和更清晰的编写语言,但如果您重视灵活性和额外功能,您可能会喜欢Uno。截至目前为止,Uno的编辑器体验也更加出色,但也许这会发生改变!我将密切关注它们两个。👀

另外,还有一些值得一提的库:

  • MasterCSS:并没有吸引我。它似乎没有非常注重限制,并且其语言感觉不太符合人体工程学。
  • Twind:编辑器插件尚未更新以适应最新版本。
  • TypeWind(以及类似的库):我非常赞赏在没有额外编辑器插件的情况下提供良好开发体验的努力,但基于TS的类名非常不符合人体工程学 😅