iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
JavaScript

JavaScript為什麼筆記本系列 第 15

Day 15|Figma 裡的 Gap、Fill、Hug,到了 React 到底怎麼變成 Tailwind?

  • 分享至 

  • xImage
  •  

Day 14 第一次認真看 Figma。

昨天在 CRM UI Kit 的登入畫面裡,我點到包住兩顆按鈕的 Frame,右邊看到:

Auto layout
Flow: Horizontal
Width: Fill
Height: Hug
Gap: 9
Padding: 0

昨天先停在「看懂」。

今天不想再只用文字解釋,所以我把昨天的 Figma 節點重新打開,然後真的開 React 專案動手做。

核心問題很簡單:

Figma 裡看到的 Horizontal、Fill、Hug、Gap 9,到了 React 到底要怎麼寫?


Tailwind 先不要想得太神祕

我以前看到這種東西:

<div className="flex w-full gap-[9px]">

第一個反應其實是:這又是哪一套語法?

這裡其實混合了兩件事情:

className
→ React / JSX 用來指定 CSS class 的寫法
→ 一般 HTML 裡會寫成 class

className 裡面的:

flex
→ display: flex

w-full
→ width: 100%

gap-[9px]
→ gap: 9px

所以這整句:

<div className="flex w-full gap-[9px]">

大概可以先把它想成:

<div
  style={{
    display: "flex",
    width: "100%",
    gap: "9px",
  }}
>

Tailwind CSS 是 CSS framework,但它不是另一套瀏覽器排版引擎。

瀏覽器最後跑的還是 CSS。

Tailwind 比較像是把常用 CSS 規則整理成很多小工具,讓我直接在 JSX 的 className 裡組起來。

這裡的 [9px] 可以先記成:Tailwind 允許直接指定任意值。後面實際做到 Gap 9 時,再仔細看它代表什麼。

既然 CSS 本來就能寫,為什麼還要 Tailwind?

Tailwind 並沒有讓瀏覽器突然多出新的排版能力。

它主要改變的是工程師組 UI 的方式

一般 CSS 常常會是:

看到 Figma
↓
想成 CSS
↓
幫這塊 UI 取一個 class 名稱
↓
切到 CSS 檔案寫規則
↓
回 JSX 掛上 class

如果專案使用 Tailwind,就可以比較直接:

看到 Figma
↓
想成 CSS
↓
在 JSX 裡用 utility class 組出來

例如:

<div className="flex w-full gap-[9px]">

對 React 這種元件化開發來說,樣式和元件會放得比較近。我們在調畫面時,也比較不用一直在 JSX 和 CSS 檔案之間來回找。

另外,正式專案通常還會把 spacing、顏色、字體、圓角等規則整理成 design system。

這時 Tailwind 的 gap-2px-4rounded-xl 這類 utility class,也能幫大家比較容易沿用同一套尺度。

但 Tailwind 不是「一定比較好」。

當 class 很多時:

<button className="flex items-center justify-center rounded-xl border px-4 py-3 font-semibold ...">

也可能變得很長。

所以我現在先把它理解成:

Tailwind 不是取代 CSS,而是一種讓我們更快組合 CSS 規則的工作方式。


先真的把 Tailwind 裝進 Vite

這次直接用這個系列的 vite-why-lab 做實驗。

安裝:

npm install -D tailwindcss @tailwindcss/vite

接著在 vite.config.js 加上 Tailwind 的 Vite plugin:

import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [react(), tailwindcss()],
})

src/index.css 則先縮到最小:

@import "tailwindcss";

這次不是「文章裡假設有 Tailwind」。

我真的跑了:

npm run build

Vite build 有成功,才繼續下面的實驗。


第一步:先放兩顆完全沒樣式的按鈕

我先故意不寫 Tailwind:

function App() {
  return (
    <main>
      <h1>Day 15 Tailwind Lab</h1>

      <div>
        <button>Sign In</button>
        <button>Sign Up</button>
      </div>
    </main>
  )
}

畫面真的很樸素。

但這反而很重要。

因為接下來每加一個 class,我都可以直接看它到底改了什麼。


第二步:Figma 的 Horizontal → flex

昨天 Figma 顯示:

Flow: Horizontal

如果翻成 CSS 心智模型,大概就是:

display: flex;

Tailwind 寫法:

<div className="flex">
  <button>Sign In</button>
  <button>Sign Up</button>
</div>

所以這一次我不是背:

flex = 橫排

而是知道:

Figma Horizontal Auto Layout
↓
CSS Flexbox
↓
Tailwind flex

第三步:Figma 的 Gap 9 → gap-[9px]

接著是昨天真的看到的:

Gap: 9

先直接做最忠實的版本:

<div className="flex gap-[9px]">

這裡的方括號代表我直接指定任意值。

但這不代表以後 Figma 看到 9px,就永遠都要寫 gap-[9px]

正式專案通常會有 spacing scale,例如 8px、12px、16px。

設計系統如果已經有接近的規則,可能會選既有 spacing,而不是讓每個地方都長出一個神奇數字。

今天先忠實重現,之後再談 design system。


Fill 不是永遠等於 w-full

這是昨天最容易誤會的地方。

Figma 的 Fill 比較像「尺寸策略」:

父層能分給我多少空間,我就去使用那些空間。

例如外層容器要吃滿可用寬度,可以是:

<div className="w-full">

但是兩顆按鈕要一起平分空間時,我反而用了:

<button className="flex-1">Sign In</button>
<button className="flex-1">Sign Up</button>

所以不能死背:

Figma Fill = Tailwind w-full

要先看父層怎麼排。


Hug 有時候反而代表「不要寫死高度」

Figma 還寫了:

Height: Hug

如果我只看到畫面最後高度大概 46px,就直接:

className="h-[46px]"

反而可能把 Hug 的意思弄丟。

這次按鈕是靠:

className="px-4 py-3"

讓「文字高度 + 上下 padding」自然把按鈕撐開。

內容改變時,元件還能跟著長。

這比把每顆按鈕高度硬鎖死,更接近 Hug contents 的思維。


最後真的把它做成一個像樣的登入區塊

<div className="flex w-full gap-[9px]">
  <button className="flex-1 rounded-xl bg-violet-600 px-4 py-3 font-semibold text-white">
    Sign In
  </button>

  <button className="flex-1 rounded-xl border border-slate-300 bg-white px-4 py-3 font-semibold">
    Sign Up
  </button>
</div>

這次程式碼也不是只存在文章裡。

我是真的在 App.jsx 裡把這些 Tailwind class 寫進去。


現在再看這串,就沒有那麼像亂碼了

flex
→ 子元素用 Flexbox 排列

w-full
→ 使用可用寬度

gap-[9px]
→ 子元素之間 9px

flex-1
→ 一起分配剩餘空間

rounded-xl
→ 圓角

px-4 / py-3
→ 左右 / 上下 padding

font-semibold
→ 字體稍粗

最大的差別不是今天多背了幾個 class。

而是開始能走:

Figma
↓
Layout 規則
↓
CSS 心智模型
↓
Tailwind
↓
React JSX

而不是:

Figma 看到 9px
↓
找一個 Tailwind 9px
↓
貼上

下一個問題:畫面做好了,但它還不會「變」

現在兩顆按鈕已經有樣子了。

但是按下 Sign In 之後,目前什麼事情都不會發生。

假設登入前:

const user = null

登入後:

const user = {
  name: 'Anthony'
}

React 要怎麼知道資料變了,而且畫面也應該跟著更新?

這就會碰到下一個問題:

登入狀態為什麼不能只寫成普通的 const?React 的 state 到底在解決什麼?

這就是 Day 16 要接的地方。


上一篇
Day 14|Figma 速覽:從 Community 範例快速到 React Component
下一篇
Day 16|登入狀態為什麼不能只寫成 `const`?先把 `useState` 這一行看懂
系列文
JavaScript為什麼筆記本20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言