「及時」模式:全新世代的 Tailwind CSS
Tailwind CSS on GitHub

功能優先 (Utility First)

從組合過的原生功能,來建立起複雜的元件。

Overview

一般來說,你要透過寫 CSS 來幫你網站上的某些東西增加樣式。

在傳統的方法,如果你要客製化的設計,你就必須要自定義一個 CSS 名稱

ChitChat

你有一則新訊息

<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">你有一則新訊息</p>
  </div>
</div>

<style>
  .chat-notification {
    display: flex;
    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;
    padding-top: 0.25rem;
  }
  .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,你就可以用 Tailwind 已經存在、預先設計好的 class 名稱直接在 html 修改你的樣式。

以 Tailwind 提供的 class 名稱去自訂你的 CSS

ChitChat

你有一則新訊息

<div class="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-md flex items-center space-x-4">
  <div class="flex-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-gray-500">你有一則新訊息</p>
  </div>
</div>

在上面這個範例,我們用了:

這個方法讓我們不用撰寫任何一行的 CSS,就能夠實現完整的客製化元件設計。

我知道你現在在想什麼:「這太殘暴了吧…看起來也太亂太可怕了…」。不過你沒有錯,這的確有點醜。事實上,第一次看到這個方法的時候幾乎不太可能認為這是一個好主意,不過你必須試試看,試了就知道了。

但你實際用這個方法建構一次時,你就會很快的注意到一些真的非常讚的地方:

  • 你不用再浪費力氣去想 class 名稱:不會再因為只是要增加某些樣式而創了一些像是 sidebar-inner-wrapper 這樣子傻傻的 class 名稱,也不用再因為覺得「flex 容器的名稱怎麼想都很抽象」而痛苦。
  • 你 CSS 的量不會再變多:用傳統的方法,只要每次增加新功能時 CSS 的檔案就會變大。但有了功能性 class,你就很少再寫新的 CSS 樣式了,因為一切都是可以重複使用的。
  • 改樣式時感覺更安心:CSS 是作用於整個網站的,所以你永遠不會知道你改變一個樣式的同時把其他地方的排版給弄爆了。Class 只作用於你指定的 HTML 元素,所以你完全不用擔心改樣式時會把什麼東西弄壞。

當你僅僅只透過預定義的功能性 class 來撰寫 HTML 樣式時,你就會意識到那生產力有多高,反而用以前的方式去寫會是一種折磨。


為何不使用 inline style 就好?

對於這個方法常見的反應大多都是「這難道不是 inline style 嗎?」,某些情況下來說應該是,但實際上是 — 你是正在幫元素直接使用樣式,而不是幫它們指定 class 名稱後再幫那個 class 設定樣式。

但使用功能性 class 有幾個優於 inline style 的點:

  • 有約束的設計:使用 inline style,每個數值都是一個實體數字 (magic number)。有了功能 (utilities),你則是從一個預定義的設計系統中挑選樣式,令我們能更輕鬆簡單的建構出與視覺一置的使用者介面 (UI)。
  • 響應式設計:你無法在 inline style 使用 media query 來做響應式設計,但你可以使用 Tailwind 的響應式功能 (responsive utilities) 來更簡單地建構出完全響應式的介面。
  • Hover、focus 及其他狀態:inline styles 無法標記諸如 hover、focus 等的狀態,但 Tailwind 狀態變化模式的功能性 class 能簡單的幫那些狀態增加樣式。

這個元件完全支援響應式並包含一個有 hover 及 focus 樣式的按鈕,而且完全用功能性 class 建置。

Woman's Face

Erin Lindford

產品工程師

<div class="py-8 px-8 max-w-sm mx-auto bg-white rounded-xl shadow-md 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:flex-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-gray-500 font-medium">
        產品工程師
      </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">傳送訊息</button>
  </div>
</div>

關於可維護性

透過使用功能優先的方式來管理經常重複的功能組合,使可維護性最大化。

這可以透過提取成元件 的方式輕鬆解決,並成為元件或者模板的一部份。

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

你也可以用 Tailwind 的特色指令 @apply 來整合並簡化常用的 CSS 樣式,降低建構 class 的複雜度。

<!-- 使用功能優先 Class -->
<button class="py-2 px-4 font-semibold rounded-lg shadow-md text-white bg-green-500 hover:bg-green-700">
  按我一下
</button>

<!-- 用 @apply 提取 Class -->
<button class="btn btn-green">
  按鈕
</button>

<style>
  .btn {
    @apply py-2 px-4 font-semibold rounded-lg shadow-md;
  }
  .btn-green {
    @apply text-white bg-green-500 hover:bg-green-700;
  }
</style>

此外,事實證明維護功能優先的 CSS 專案比起維護大量 CSS 程式碼要來的簡單多了,僅僅是因為 HTML 比 CSS 還容易維護。像是 GitHub、Heroku、Kickstarter、Twitch、Segment 還有其他等等的大公司都是這個方法的成功案例

如果你想聽聽看其他人使用這個方法的經驗,可以瀏覽一下這些文章:

還想了解更多,請看 John Polacek 所撰寫的 The Case for Atomic/Utility-First CSS