1. 核心概念
  2. 工具优先的基础

概述

传统上,每当你需要在 Web 上设置样式时,你都会编写 CSS。

¥Traditionally, whenever you need to style something on the web, you write CSS.

使用定制设计需要定制 CSS 的传统方法

ChitChat

You have a new message!

<div class="chat-notification">
  <div class="chat-notification-logo-wrapper">
    <img class="chat-notification-logo" src="/img/logo.svg" alt="ChitChat Logo">
  </div>
  <div class="chat-notification-content">
    <h4 class="chat-notification-title">ChitChat</h4>
    <p class="chat-notification-message">You have a new message!</p>
  </div>
</div>

<style>
  .chat-notification {
    display: flex;
    align-items: center;
    max-width: 24rem;
    margin: 0 auto;
    padding: 1.5rem;
    border-radius: 0.5rem;
    background-color: #fff;
    box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
  }
  .chat-notification-logo-wrapper {
    flex-shrink: 0;
  }
  .chat-notification-logo {
    height: 3rem;
    width: 3rem;
  }
  .chat-notification-content {
    margin-left: 1.5rem;
  }
  .chat-notification-title {
    color: #1a202c;
    font-size: 1.25rem;
    line-height: 1.25;
  }
  .chat-notification-message {
    color: #718096;
    font-size: 1rem;
    line-height: 1.5;
  }
</style>

使用 Tailwind,你可以通过直接在 HTML 中应用预先存在的类来设置元素样式。

¥With Tailwind, you style elements by applying pre-existing classes directly in your HTML.

使用工具类构建自定义设计,无需编写 CSS

ChitChat

You have a new message!

<div class="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-lg flex items-center space-x-4">
  <div class="shrink-0">
    <img class="h-12 w-12" src="/img/logo.svg" alt="ChitChat Logo">
  </div>
  <div>
    <div class="text-xl font-medium text-black">ChitChat</div>
    <p class="text-slate-500">You have a new message!</p>
  </div>
</div>

在上面的例子中,我们使用了:

¥In the example above, we’ve used:

  • Tailwind 的 flexboxpadding 工具(flexshrink-0p-6)用于控制整体卡片布局

    ¥Tailwind’s flexbox and padding utilities (flex, shrink-0, and p-6) to control the overall card layout

  • max-widthmargin 工具(max-w-smmx-auto)用于限制卡片宽度并将其水平居中

    ¥The max-width and margin utilities (max-w-sm and mx-auto) to constrain the card width and center it horizontally

  • 背景颜色边框半径box-shadow 工具(bg-whiterounded-xlshadow-lg)用于设计卡片的外观

    ¥The background color, border radius, and box-shadow utilities (bg-white, rounded-xl, and shadow-lg) to style the card’s appearance

  • widthheight 工具(w-12h-12)用于调整徽标图片的大小

    ¥The width and height utilities (w-12 and h-12) to size the logo image

  • space-between 工具 (space-x-4) 用于处理徽标和文本之间的间距

    ¥The space-between utilities (space-x-4) to handle the spacing between the logo and the text

  • 用于设置卡片文本样式的 字体大小文本颜色font-weight 工具(text-xltext-blackfont-medium 等)

    ¥The font size, text color, and font-weight utilities (text-xl, text-black, font-medium, etc.) to style the card text

这种方法允许我们实现完全自定义的组件设计,而无需编写一行自定义 CSS。

¥This approach allows us to implement a completely custom component design without writing a single line of custom CSS.

现在我知道你在想什么,“这是一场暴行,多么可怕的一团糟!“,你是对的,这有点丑陋。事实上,当你第一次看到它时,几乎不可能认为这是一个好主意 - 你必须实际尝试一下。

¥Now I know what you’re thinking, “this is an atrocity, what a horrible mess!” and you’re right, it’s kind of ugly. In fact it’s just about impossible to think this is a good idea the first time you see it — you have to actually try it.

但是一旦你以这种方式实际构建了一些东西,你很快就会注意到一些非常重要的好处:

¥But once you’ve actually built something this way, you’ll quickly notice some really important benefits:

  • 你不会浪费精力发明类名。不再为了能够设置样式而添加像 sidebar-inner-wrapper 这样愚蠢的类名,也不再为真正只是一个 flex 容器的东西的完美抽象名称而苦恼。

    ¥You aren’t wasting energy inventing class names. No more adding silly class names like sidebar-inner-wrapper just to be able to style something, and no more agonizing over the perfect abstract name for something that’s really just a flex container.

  • 你的 CSS 停止增长。使用传统方法,每次添加新功能时,你的 CSS 文件都会变大。使用工具,一切都可以重用,因此你几乎不需要编写新的 CSS。

    ¥Your CSS stops growing. Using a traditional approach, your CSS files get bigger every time you add a new feature. With utilities, everything is reusable so you rarely need to write new CSS.

  • 做出改变感觉更安全。CSS 是全局的,你永远不知道在进行更改时会破坏什么。HTML 中的类是本地的,因此你可以更改它们而不用担心其他东西会破坏。

    ¥Making changes feels safer. CSS is global and you never know what you’re breaking when you make a change. Classes in your HTML are local, so you can change them without worrying about something else breaking.

当你意识到只使用预定义的工具类在 HTML 中工作是多么高效时,以任何其他方式工作都会感觉像是一种折磨。

¥When you realize how productive you can be working exclusively in HTML with predefined utility classes, working any other way will feel like torture.


为什么不直接使用内联样式?

¥Why not just use inline styles?

对这种方法的常见反应是想知道,“这不只是内联样式吗?“,在某些方面确实如此 - 你将样式直接应用于元素,而不是为它们分配一个类名,然后对该类进行样式设计。

¥A common reaction to this approach is wondering, “isn’t this just inline styles?” and in some ways it is — you’re applying styles directly to elements instead of assigning them a class name and then styling that class.

但是使用实用类比内联样式有几个重要的优势:

¥But using utility classes has a few important advantages over inline styles:

  • 有约束的设计。使用内联样式,每个值都是一个幻数。使用工具,你可以从预定义的 设计系统 中选择样式,这使得构建视觉上一致的 UI 变得更加容易。

    ¥Designing with constraints. Using inline styles, every value is a magic number. With utilities, you’re choosing styles from a predefined design system, which makes it much easier to build visually consistent UIs.

  • 响应式设计。你不能在内联样式中使用媒体查询,但可以使用 Tailwind 的 响应工具 轻松构建完全响应式界面。

    ¥Responsive design. You can’t use media queries in inline styles, but you can use Tailwind’s responsive utilities to build fully responsive interfaces easily.

  • 悬停、聚焦和其他状态。内联样式无法针对悬停或聚焦等状态,但 Tailwind 的 状态变量 可以轻松地使用工具类对这些状态进行样式设置。

    ¥Hover, focus, and other states. Inline styles can’t target states like hover or focus, but Tailwind’s state variants make it easy to style those states with utility classes.

这个组件是完全响应式的,包括一个带有悬停和聚焦样式的按钮,并且完全是用工具类构建的:

¥This component is fully responsive and includes a button with hover and focus styles, and is built entirely with utility classes:

Woman's Face

Erin Lindford

Product Engineer

<div class="py-8 px-8 max-w-sm mx-auto bg-white rounded-xl shadow-lg space-y-2 sm:py-4 sm:flex sm:items-center sm:space-y-0 sm:space-x-6">
  <img class="block mx-auto h-24 rounded-full sm:mx-0 sm:shrink-0" src="/img/erin-lindford.jpg" alt="Woman's Face" />
  <div class="text-center space-y-2 sm:text-left">
    <div class="space-y-0.5">
      <p class="text-lg text-black font-semibold">
        Erin Lindford
      </p>
      <p class="text-slate-500 font-medium">
        Product Engineer
      </p>
    </div>
    <button class="px-4 py-1 text-sm text-purple-600 font-semibold rounded-full border border-purple-200 hover:text-white hover:bg-purple-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-offset-2">Message</button>
  </div>
</div>

可维护性问题

¥Maintainability concerns

使用工具优先方法时最大的可维护性问题是管理通常重复的工具组合。

¥The biggest maintainability concern when using a utility-first approach is managing commonly repeated utility combinations.

提取组件和部分 很容易解决这个问题,使用 编辑器和语言功能 喜欢多光标编辑和简单循环。

¥This is easily solved by extracting components and partials, and using editor and language features like multi-cursor editing and simple loops.

<!-- PrimaryButton.vue -->
<template>
  <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
    <slot/>
  </button>
</template>

除此之外,维护实用优先的 CSS 项目比维护大型 CSS 代码库要容易得多,原因很简单,因为 HTML 比 CSS 更容易维护。GitHub、Netflix、Heroku、Kickstarter、Twitch、Segment 等大公司都在使用这种方法取得了巨大成功。

¥Aside from that, maintaining a utility-first CSS project turns out to be a lot easier than maintaining a large CSS codebase, simply because HTML is so much easier to maintain than CSS. Large companies like GitHub, Netflix, Heroku, Kickstarter, Twitch, Segment, and more are using this approach with great success.

如果你想了解其他人使用此方法的经验,请查看以下资源:

¥If you’d like to hear about others’ experiences with this approach, check out the following resources:

如需更多信息,请查看由 约翰波拉切克 策划的 原子/工具优先 CSS 的案例

¥For even more, check out The Case for Atomic/Utility-First CSS, curated by John Polacek.