TailwindCSS:增加了复杂性,没有任何作用。

2025-05-25

TailwindCSS:增加了复杂性,没有任何作用。

如果您从事前端工作,您可能听说过很多关于 TailwindCSS 的事情,它是一个 CSS 库,与 Bootstrap 非常相似。然而,与 Bootstrap不同的是,Tailwind 采用了不同的方法——它完全由“工具类”组成。

我可不是它的粉丝。我闻了一下,很快就知道这个名字很贴切:它就像放屁一样受欢迎,也很有用。

在开始之前,我先解释一下什么是工具类。假设你有很多组件,其中很多都需要 CSS 样式属性“display: flex;”。与其在 CSS 中一遍又一遍地重复写这个属性,不如创建一个名为“flex”的类。

.flex {
  display: flex;
}
Enter fullscreen mode Exit fullscreen mode

然后,在每个需要弯曲的组件中,添加“flex”类。

这并非坏事。我自己也编写并使用过很多实用类,尤其是在没有 CSS-in-JS 解决方案或 Sass/SCSS 等预处理器的情况下编写 CSS 时。

Tailwind 将这个概念发挥到了极致,其理念是你几乎不需要编写 CSS,你只需要根据需要应用的样式编写不同的类。

这是一个有趣的选择,因为......

这只是带有额外步骤的内联样式

这只是带有额外步骤的内联样式。

就是这样。 写<div class="flex">foo</div>和 写 的效果完全一样<div style="display: flex;">foo</div>。嗯——略有不同,内联样式的优先级比类高,但这在本例中并不重要。

所以——考虑到这一点,除了 CSS 优先级之外,任何你反对在代码库中使用内联样式的论点,也都是反对使用 Tailwind 的论点。例如:Lifewire:避免在 CSS 设计中使用内联样式。或者StackOverflow:内联 CSS 有什么不好?。或者LogRocket:为什么不应该在生产环境的 React 应用中使用内联样式

我知道,用其他用户对内联样式的批评来解释 Tailwind 的问题似乎有点懒,但它确实是一对一的映射。它只是多了额外步骤的内联样式而已。

Tailwind 与内联样式存在一些共同的问题:

它是湿的,不是干的。

当您想要对网站样式进行重大更改时,如果您使用了实用类,则需要仔细检查这些实用类的每一次使用(即每个组件),并直观地确定需要更新的内容。例如,假设您公司的主色调是蓝色。您的网站上会有很多蓝色元素,并使用诸如“text-blue-500”或“bg-blue-300”之类的标记来确定不同的蓝色深浅。这完全没问题,直到您的公司决定进行品牌重塑,网站上的所有按钮(仅限按钮)都需要改为红色。

现在你必须逐个检查每个组件,手动将“text-blue-500”改为“text-red-500”。1000次修改就意味着1000次引入bug的机会。这几乎就是DRY原则的典型例子

或者,如果你使用的是常规的 CSS,你可能的做法是创建一个名为“.button”的类。你只需在该类中修改一行代码:“background-color: 'red';”。任何使用该类定义的元素现在都将变成红色。

这引出了下一点:

HTML 应该只关注页面的结构,而不是页面的样式。

在开发过程中,人们经常谈论关注点分离。CSS 模块(尤其是 .vue 文件)在很大程度上消除了需要将网站相同基本构建块的结构、行为和样式隔离在单独文件夹中的观念,但关注点分离仍有其道理。也就是说,代码的每个部分都应该“松耦合、高内聚”。

换句话说,您的 HTML(结构语法)不应该包含有关样式应该是什么的信息,它应该只包含有关页面结构的信息。

事实上,发明 CSS 的最终原因, CSS 整个事业的全部意义……就是为了将内容呈现分开。

而实现这一目标的方法是通过“class”属性。

“类”的真正意义在于,你可以告诉计算机一个元素什么——也就是描述元素的内容。一旦你定义了内容,你只需要决定该类型的内容应该是什么样子。

这不仅意味着您可以更改元素的外观而不必担心页面的底层结构,还意味着您可以使用这些类来描述元素是什么。事实上,BEM 命名语法的部分原因是,BEM 名称不仅告诉您组件是什么,还告诉您它与文档中其他组件的关系。

请记住,我们编写代码是为了两类受众:一类是计算机本身,它不在乎代码的外观,只要能运行就行;另一类是你的程序员同事。他们越容易快速识别程序的各个部分以及它们之间的相互关系,他们就能越快地修复错误、添加功能,并为组织带来价值。

这让我们想到:

很难读

如果你查看一些包含 Tailwind 的 HTML,你可能会觉得这些 HTML 看起来很“杂乱”,甚至“丑陋”。这话没错,但你并没有抓住重点。

不管你对内联样式有什么看法,但它们至少提供了足够的上下文让你了解发生了什么。Tailwind 代码中充斥着语义晦涩的缩写;其中大多数只是对众所周知的 CSS 属性的重新定义。

更糟糕的是,如果它们不是重新定义,就可能变得非常隐晦。Tailwind 更倾向于使用带前缀的类名,而不是媒体查询。以下是Aleksandr Hovhannisyan的一个例子

因此在 Tailwind 中:

<div
  class="w-16 h-16 rounded text-white bg-black py-1 px-2 m-1 text-sm md:w-32 md:h-32 md:rounded-md md:text-base lg:w-48 lg:h-48 lg:rounded-lg lg:text-lg"
>
  Yikes.
</div>

Enter fullscreen mode Exit fullscreen mode

可以表示为:

<style>
.thing {
  width: 16px;
  height: 16px;
  color: white;
  background-color: black;
  padding: 0.25rem 0.5rem;
  margin: 0.25rem;
  border-radius: 0.25rem;
  font-size: 0.875rem;
  line-height: 1.25rem;
}

@media screen and (min-width: 768px) {
  .thing {
    width: 32px;
    height: 32px;
    border-radius: 0.375rem;
    font-size: 1rem;
    line-height: 1.5rem;
  }
}

@media screen and (min-width: 1024px) {
  .thing {
    width: 48px;
    height: 48px;
    border-radius: 0.5rem;
    font-size: 1.125rem;
    line-height: 1.75rem;
  }
}

</style>
<div class="thing">Yikes.</div>
Enter fullscreen mode Exit fullscreen mode

现在,我承认,第一个例子需要编写的代码少了很多,但请看第二个例子是如何在特定断点处明确定义高度和宽度的。

它很冗长 - 就像原始 CSS 通常那样,但还有其他解决方案 - 例如 Sass/SCSS,或诸如 Emotion、Styled Components 等解决方案,它们允许您使用更简洁的语法而不会丢失其背后的凝聚力。

再说一遍,这是程序员的101。这就是为什么高级开发人员会批评初级开发人员将变量命名为“const h = 10”而不是“const height = 10”。

后者比前者更易读的另一个原因是,Tailwind 的类是水平排列的,而 CSS 是垂直书写的。文本越宽,读者的眼睛就越难跳到下一行,在一大堆水平文本中找到你想要的某个特定单词也就越难。

我敢打赌,当您看到 Tailwind 代码示例上的水平滚动条时,您的眼睛就开始呆滞了,不是吗?

你会失去很多标准 CSS 内置的功能

我不想过多地谈论这一点,但需要指出的是,由于 Tailwind 不允许你使用 CSS 的许多基本功能,你不能像下面这样将选择器链接在一起:

.foo:focus,
.foo:active,
.foo:hover {
  /* css code */
}
Enter fullscreen mode Exit fullscreen mode

您不能使用组合器。

.foo p {
  /* all p that are decendants of a .foo */
}
.foo > p {
  /* all p that are direct children of a .foo */
}
.foo + p {
  /* all p that are directly -after- a .foo */
}
.foo ~ p {
  /* all p that are siblings of a .foo */
}
Enter fullscreen mode Exit fullscreen mode

它解决了一个不存在的问题。

最疯狂的事情之一是 Tailwind 的实用类范式存在明显的局限性。如果你想将相关的样式组合在一起,会发生什么?例如,很少会在没有“justify-content: {value}”的情况下使用“display:flex;”。CSS 允许你将这些样式组合成(等等),即“类”

Tailwind 还有一个工具可以将相关的类分组在一起,叫做@apply。它是一种特殊的非标准语法,位于 CSS 文件中(一个指令),允许你将一系列 Tailwind 类串联在一起,并将它们全部放在一个类名下。

也就是说,这完全违背了实用类范式背后的初衷。如果你最终不得不使用@apply,那么为什么不直接使用普通的、常规的 CSS 呢?它更容易阅读、理解和修改,而且不需要特殊的工具或解析。CSS 语法可能很复杂,但自 90 年代末以来一直相当稳定,短期内不会发生根本性的变化。

我想和你一起做一个非常简单的心理实验。

想象一下,一个从未开发过 CSS 的世界,但出现了类似 Tailwind 的东西。也就是说,网页只能通过重复这些单独的类名来设置样式……大概是通过使用 table 标签进行布局。(为了让你了解我的年龄,我曾在 1996 年高三暑期打工编写网页代码——我们用了很多 table 标签。)

如果你能突破 Tailwind 的限制,转而使用CSS,难道你不觉得这是一个巨大的飞跃吗?富有表现力的语法!语义化的命名!样式分组!选择器和组合器!这就像第一次从 Assembly 转到 C 语言一样。如果真是这样,我们为什么要考虑用功能更少、更复杂、代码库质量更差、最终可能面临供应商锁定的语言来替代 CSS 呢?

如果您想要比 CSS 更好的解决方案,那么已经解决方案了。

所以,Tailwind 的很多宣传都说它可以让你摆脱 CSS。我知道,每个人都知道 CSS 很难用——尤其是在你的代码库比较老旧,CSS 写得不太好的时候。

但在大多数情况下,CSS 上还有其他更好的改进,确实可以简化样式设置。各种 CSS-in-JS 解决方案,让您能够利用 JavaScript 的强大功能创建动态类定义;还有 Sass/SCSS/LESS 等预处理器;还有像 Stylelint 这样的代码检查工具;以及像 BEM/SMACSS 这样的最佳实践方法。学习这些技术需要投入成本吗?是的。您的构建链中是否需要一些工具?是的。但与 Tailwind 不同的是,所有这些解决方案都为您的代码带来了切实的好处——这是 Tailwind 无法企及的。

它实际上没有任何价值,却带来大量问题。

到头来,所有这些问题都解决了,你得到了什么?你还剩下什么?基本上,你得到的是一个可读性更低、更复杂的内联样式版本,而这种编码技术,我们在过去十年左右的时间里,一直在努力从初级开发人员中淘汰。

如果您采用 Tailwind,它将在未来几年给您和您的团队带来问题,并且很难消除它。


根据评论部分进行更新。

根据评论部分的回复提出几点说明。

如果你不喜欢某样东西,为什么要把它扔掉呢?

撰写关于坏框架的文章与撰写关于好框架的文章同样重要,原因有二。

首先,是约翰·斯图尔特·密尔的“错误观点的价值”论证——在对不正确的观点进行(善意的)论证时,人们可以通过分析和反驳得出更正确、更完整的观点。观点必须不断受到挑战,否则就会过时。事实上,“不理解对手论点的人,也就不理解自己的论点”是我努力践行的一句格言。在撰写本文时,我试图寻找 Tailwind 的优点。为什么人们喜欢它?(他们不必编写 CSS。他们可以在 HTML 中添加样式信息。他们可以编写更简洁的代码。这让他们能够做一些他们不知道如何在 CSS 中做的事情。)一旦我知道了人们为什么喜欢它,我就更好地理解了为什么我不喜欢它。(它结合了内容和呈现。这使得维护变得更加困难。语法晦涩难懂。你失去了在 CSS 中可以做的事情的能力。)

其次,有人会想:嗯,我应该把 Tailwind 添加到我的团队需要维护的应用中吗?然后他们会去谷歌搜索“TailwindCSS 的优缺点”。会有很多文章解释 Tailwind 的优缺点。这里有一篇解释 Tailwind 的缺点的文章。希望我已经提出了一个令人信服的理由,建议不要使用 Tailwind,这样未来的开发者就不用再忍受它了。

你对喜欢 Tailwind 的人很不尊重。

这不是新奥尔良爵士队。

我不喜欢新奥尔良爵士乐,所以没必要听。我也不买新奥尔良爵士乐的专辑。

我不会对我认为的新奥尔良爵士乐的音乐创作问题做出详细的批评。

但从来没有一个团队领导、产品所有者或利益相关者来找我说:“对于下一个项目,我认为团队中的每个人都必须学习如何欣赏和演奏新奥尔良爵士乐。”

工程师和开发人员经常被要求使用他们不仅不喜欢,而且会使他们的工作更加困难的技术——通常是因为决策者要么不关心软件的利弊权衡,要么根本就不了解。对于前者我们无能为力,但对于后者我们可以有所作为。

当团队领导考虑将一项新技术纳入他们的技术栈时,他们应该寻找像这样的博客文章来帮助他们评估是否值得尝试。

我的观点并非像你想象的那样:“我不喜欢 Tailwind,所以你也不应该喜欢 Tailwind”。那只是一个 12 岁孩子对科技的批判。

相反,我的观点是:“如果您选择 Tailwind 作为关键任务应用程序,那么您的工作将变得更加困难,应用程序将变得更加脆弱,并且从长远来看,您的团队将受到影响。”

但是 CSS 存在大量问题!

确实如此。而且肯定有比纯 CSS 更好的解决方案。但 Tailwind 不在其中。

假设在 20 世纪 90 年代,建造房屋的唯一方法是用扁平的石头敲钉子(CSS)。然后,大约在 2000 年代中期,一个非常聪明的人发明了“锤子”。(SCSS)虽然需要进行调整,并且需要学习一种新工具,但它的效果要好得多。

大约在 2010 年代初期到中期,另一个人发明了钉枪(CSS-in-JS)。它的功能和锤子类似,但你必须知道如何使用它。虽然存在一些优缺点,但总的来说,选择使用锤子或钉枪的人通常都能顺利完成工作。许多人经常在觉得手动锤合适的时候使用手动锤,而在需要的时候使用钉枪。木工的世界就是这样美好的。

然后在 2017 年,有人走到木匠面前说:“嘿,看看我这样做会发生什么!”然后开始用装有子弹的左轮手枪 (Tailwind) 的枪托敲钉子。

它的支持者很快指出,建造房屋比敲打岩石更有效。

“但这是一把上了膛的枪,它可能会走火射人。”
“我还没遇到过这种情况。”
“你为什么不用锤子?或者射钉枪?”
“我不喜欢锤子或射钉枪。”“
我能理解你为什么不用,但即使用石头,从长远来看也更安全。”
“但用石头太难了,效率太低了。”
“我不是说要用石头。我是说,锤子已经解决了你用石头的问题,但即使是石头,也比上了膛的枪好,因为它不会射人。”
“但我喜欢我的枪。”
“我想如果你在自家地盘的小项目上使用枪应该没问题,但是……”
“不,我是工头。从现在开始,工地上的每个人都要用上了膛的枪,因为它们太棒了。”


更新:2021年5月9日 - 请查看Mykolas Mankevicius 的这篇博客文章,它试图反驳这篇文章。我当然不同意,但我认为这会加剧争论。如果你正在读这篇文章,正在考虑是否使用 Tailwind,你应该听听这个问题“另一方”的看法。

同意,但觉得我的文风可能太粗鲁?看看Benoît Rouleau 对这篇名为《Tailwind CSS 可能不适合你》的文章的看法。

Cher在“性别歧视、种族歧视、有害积极性和 TailwindCSS”中谈到了这篇文章得到的一些反响,以及它与我们自身无意识偏见的关系。

文章来源:https://dev.to/kerryboyko/tailwindcss-adds-complexity-does-nothing-3hpn
PREV
10 个优秀开发者作品集示例👩‍💻🧑‍💻💼,助您灵感迸发🦄 简介 Brittany Chiang Riccardo Zanutta Patrick David Fabian adeola. Adrien Gervaix SANJOO Matthew Williams Jack. Bruno Simon 结束
NEXT
9 个 Promise 技巧 1. 你可以在 .then 中返回一个 Promise 2. 每次执行 .then 时都会创建一个新的 Promise 3. Promise 会为每个人解决/拒绝 4. Promise 构造函数不是解决方案 5. 使用 Promise.resolve 6. 使用 Promise.reject 7. 使用 Promise.all 8. 不要害怕拒绝,或者不要在每个 .then 后附加多余的 .catch 9. 避免 .then 地狱