從組合過的原生功能,來建立起複雜的元件。
一般來說,你要透過寫 CSS 來幫你網站上的某些東西增加樣式。
在傳統的方法,如果你要客製化的設計,你就必須要自定義一個 CSS 名稱
你有一則新訊息
<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
你有一則新訊息
<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>
在上面這個範例,我們用了:
flex
, flex-shrink-0
, and p-6
) 去控制整個卡片的排版max-w-sm
和 mx-auto
) 來約束卡片寬度以及將卡片水平置中bg-white
、rounded-xl
和 shadow-md
) 來幫卡片外觀增添樣式w-12
and h-12
) 幫 logo 調整大小space-x-4
) 來處理 logo 與文字間的距離text-xl
, text-black
, font-medium
, etc.) 來改變卡片中文字的樣式這個方法讓我們不用撰寫任何一行的 CSS,就能夠實現完整的客製化元件設計。
我知道你現在在想什麼:「這太殘暴了吧…看起來也太亂太可怕了…」。不過你沒有錯,這的確有點醜。事實上,第一次看到這個方法的時候幾乎不太可能認為這是一個好主意,不過你必須試試看,試了就知道了。
但你實際用這個方法建構一次時,你就會很快的注意到一些真的非常讚的地方:
sidebar-inner-wrapper
這樣子傻傻的 class 名稱,也不用再因為覺得「flex 容器的名稱怎麼想都很抽象」而痛苦。當你僅僅只透過預定義的功能性 class 來撰寫 HTML 樣式時,你就會意識到那生產力有多高,反而用以前的方式去寫會是一種折磨。
對於這個方法常見的反應大多都是「這難道不是 inline style 嗎?」,某些情況下來說應該是,但實際上是 — 你是正在幫元素直接使用樣式,而不是幫它們指定 class 名稱後再幫那個 class 設定樣式。
但使用功能性 class 有幾個優於 inline style 的點:
這個元件完全支援響應式並包含一個有 hover 及 focus 樣式的按鈕,而且完全用功能性 class 建置。
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。