为什么我不推荐 Tailwind CSS
I don't recommend Tailwind CSS
Tailwind CSS 虽然流行且能快速构建界面,但我认为在中型或大型项目中需三思。它迫使开发者记忆大量类名,模糊了结构与设计的界限,且命名规则并不总是一致。更关键的是,它提供的任意值功能破坏了设计系统的约束,让开发者误以为掌握了 CSS,实则只是熟悉了抽象层。如今,现代原生 CSS 已具备 Cascade Layers、嵌套和容器查询等强大功能,Tailwind 的必要性值得重新审视。在盲目采用之前,先掌握 CSS 基础或许才是更明智的选择。
系统能帮助你,但无法让你免于自身的懈怠。
HN 评论区
158- 9dev
这简直就是一场典型的“自行车棚辩论”(bikeshedding)。虽然你不推荐它,但使用 Tailwind 的项目确实在运行,而且已经运行了好多年。你可以让新开发者快速上手,并立即开始高效贡献。同样,你在几个月甚至几年后重新接手工作时,也不必费力回忆或重新摸索你的样式层是如何工作的。
那些约定和类名很快就能变得非常自然,而且你随时可以查阅文档。这根本不像人们吹嘘的那么是个大问题。
但我觉得这篇文章最荒谬的部分是它对层叠(cascade)的抱怨:
<p class="text-red-500 text-green-500">I am some text</p>
是的,这确实行不通。但这有什么好奇怪的?!根本没有任何使用场景会认为这是个好主意!在经典 CSS 中,你可能想基于修饰类来覆盖某些样式,但在 Tailwind 里这根本就不是个事儿!如果你最终在代码中通过程序化方式层层叠加类名,那简直就是代码异味(code smell)。相反,你应该使用属性或状态修饰符,比如 `aria-hidden:opacity-0`。
- pixard
哦,我看到你有个 .button,真酷!那么,你是不是已经把整个项目的上下文都装进了脑子里,并计算了这个按钮可能拥有的所有种类、大小、颜色等迭代组合?而且做完这些后,你是不是想出了一套语义正确、清晰明了的命名方案,并且能确保它不会屈从于某个特定页面最终必然需要的 .button_checkout_special_page_cta_widget 这种命名?
没有?我也没有。我差不多十年前就彻底停止思考 CSS 了。多亏了 Tailwind。
- SebastianKra
我们需要把两种使用场景分开讨论:
用于设计系统的 CSS 是没问题的。你可以定义一个 .button[data-variant="primary"]。这很直观、性能好,也合乎逻辑。
但用于应用代码的 CSS 就很糟糕——特别是布局和排版方面。各种 flex/grid 布局与 DOM 结构紧密耦合。Tailwind 在这里非常契合:
<li class="flex flex-col">
<div class="font-medium">Title</div>
<div class="text-sm">Subtitle</div>
</li>
当你剥离掉布局甚至排版方面的顾虑后,你实际上就接近了 CSS 最初追求的“关注点分离”。HTML 决定排列,CSS 决定设计系统(颜色、边框、阴影等)。
我很少看到有人讨论这一点。以前的 Radix 团队曾写过一篇简短的笔记:https://www.radix-ui.com/blog/themes-3#the-best-of-both-worl...
- herrkanin
我曾是 Tailwind 的坚定拥趸,既爱它带来的局部推理能力,又讨厌它那些长长的类名把组件搞得乱七八糟。它对我来说一直感觉像是个生硬拼凑的 hack,但我无法反驳它带来的好处。
结果发现,CSS Modules 也能提供同样的好处,同时感觉更像是 Web 平台的一个自然延伸。我唯一彻底怀念的是函数和指令(functions and directives),希望它们能通过 mixins 提案在不久的将来登陆浏览器。
- grsmvg
作为一名拥有 26 年以上经验的前端开发者,几年前我在很多层面上都反对 Tailwind。直到我亲自试了试。
从此再也没回头过。另外,接手别人写的代码项目也没问题。只要快速看一眼中央配置文件,你就能上手干活了。
- tibastral2
你这篇文章有趣的地方在于,你大谈“传统”,但实际上这些传统是基于某些假设,而这些假设本身又是基于像“结构与样式分离是好事”这样的信念。
但这种信念只有在描述结构的语言是 HTML 或 JS 时才成立,因为它们创造的是不可复用的样式/结构片段。
但当你采取另一种方法,即一切皆函数且拥有强类型(ADT),比如使用 Haskell 时,这场辩论就结束了。因为你在代码中处理了 EVERYTHING(一切),不再将真理碎片化到那些不透明且割裂的世界中(html, js, css, database, glue, docker, ...)。
- francislavoie
说“除非你使用 @apply
- ckdot
, 这篇文章对我来说就彻底失效了。大家都知道 @apply 只是一个逃生舱(escape hatch),它本不该被使用,除非在必要时,比如为了兼容那些声明了自己类名而你需要覆盖它们的库。
这篇文章中最常被重复的论点是“逃生舱不好”,我觉得这完全荒谬。当然你想要逃生舱,否则当你遇到边缘情况时,你就无路可走,被困住了。那正是会迫使你抛弃那种方法并转向其他方案的原因。Tailwind 没有这个问题,因为它在设计之初就包含了逃生舱。
用户决定使用这些逃生舱而不是坚持某种设计,这不是 Tailwind 的错。