2021-05-15 详细介绍一下 why we should use Utility-First CSS


去年我写了一篇简单的文章解释为什么我使用 Tailwind CSS, here

团队的成员读了以后反馈说“没讲清楚”,说我又来详细介绍一下 why we should use Utility-First CSS。

什么是 Utility-First CSS

Utility-First CSS 是 Tailwind CSS 官方宣传的一种编写 CSS 的方式。

简单说:提供大量基础的 CSS classname,然后利用 CSS 的组合能力,想堆砌乐高积木一样编写 CSS。

在 Utility-First CSS 之前有哪些编写 CSS 的方式

  • BEM(Block Element Modifier)
  • SCSS
  • CSS-IN-JS
  • CSS Modules
  • ...

为什么会有这么多种方式?

要讨论这个问题,首先我们需要问 “这些开发方式试图解决什么问题?”

答:解决 CSS 模块化问题。

那么,CSS 模块化遇到了哪些问题?

  1. 全局污染
  2. 命名混乱
  3. 依赖管理不彻底
  4. 无法共享变量
  5. 代码压缩不彻底
https://github.com/camsong/blog/issues/5

在上述问题中,“全局污染” 可能是最受开发者诟病的问题了。

我以前也觉得 CSS global scope 是一个问题,但是学习了 Utility-First CSS 以后,我太爱 global scope 了。 只要使用得当,轻轻松松达到 Less is More 的效果。

对比一下 BEM CSS 和 Utility-First CSS

需求:一个简单的表格

传统风格

<style>
.table { ... }
.table-thead { ... }
.table-cell { ... }
.table-tbody { ... }
.table-row { ... }
.table-row > .table-cell { ... }
</style>

<table class="table">
  <thead class="thead">
    <tr>
      <th class="table-cell">Name</th>
      <th class="table-cell">Age</th>
      <th class="table-cell">Address</th>
    </tr>
  </thead>
  <tbody class="table-body">
    <tr class="table-row">
      <td class="table-cell">Jiang</td>
      <td class="table-cell">29</td>
      <td class="table-cell">Japan</td>
    </tr>
    <tr class="table-row">
      <td class="table-cell">Jiang</td>
      <td class="table-cell">29</td>
      <td class="table-cell">Japan</td>
    </tr>
  </tbody>
</table>

思考:

  • 有什么问题?

Utility-First 风格

<table class="bg-* m-* font-*">
  <thead class="bg-* m-* font-*">
    <tr>
      <th class="bg-* m-* font-*">Name</th>
      <th class="bg-* m-* font-*">Age</th>
      <th class="bg-* m-* font-*">Address</th>
    </tr>
  </thead>
  <tbody class="bg-* m-* font-*">
    <tr>
      <td class="bg-* m-* font-*">Jiang</td>
      <td class="bg-* m-* font-*">29</td>
      <td class="bg-* m-* font-*">Japan</td>
    </tr>
    <tr>
      <td class="bg-* m-* font-*">Jiang</td>
      <td class="bg-* m-* font-*">29</td>
      <td class="bg-* m-* font-*">Japan</td>
    </tr>
  </tbody>
</table>

思考:

  • 有什么感觉?
  • 有没有解决上面提到的问题?

Utility-First 风格 + UI Component

const Th = ({children}) => (<th class="bg-* m-* font-*">{{children}}</th>)
const Td = ({children}) => (<td class="bg-* m-* font-*">{{chilren}}</td>)

<table class="bg-* m-* font-*">
  <thead class="bg-* m-* font-*">
    <tr>
      <Th>Name</Th>
      <Th>Age</Th>
      <Th>Address</Th>
    </tr>
  </thead>
  <tbody class="bg-* m-* font-*">
    <tr>
      <Td>Jiang</Td>
      <Td>29</Td>
      <Td>Japan</Td>
    </tr>
    <tr>
      <Td>Jiang</Td>
      <Td>29</Td>
      <Td>Japan</Td>
    </tr>
  </tbody>
</table>

思考:

  • 怎么样?

背后的思想是什么?

组合由于继承

TJ

有一个 YouTube 视频,我之前分享过,大家可以看一下。https://youtu.be/3XaXKiXtNjw

总结 Why we should use Utility-First CSS

Utility-First CSS 优点

  1. 不用起名,不费脑。
  2. 责任清晰,开发速度快,容易修改,容易调试。
  3. 官方实现,bug 少

Utility-First CSS 缺点

  1. 将 CSS 结构化转移到 HTML 中,代码写的乱。(我不认同,稍后解释)
  2. 不利于爬虫(就是不让你爬)
  3. 需要记忆新的 class(比 CSS 少 10 倍)

个人观点

  • 这不是新技术,这是最基本、最核心的技术。
  • 真正提高开发效率、代码品质、且可以掌握的技术。
  • 尽早采用。