Wensity Typography
在介面中,文字承擔了絕大部分的工作。把它用對,一個樸素的頁面看起來就像經過設計;用錯,再多色彩與動態也無法挽救。此技能提供了一個可一次性設定的系統,以及可隨處套用的規則。
以下數值均為預設值。若專案已有字型系統,請保留它並改善其使用方式。僅在要求時才取代它。
1. 選擇字型家族
- 通常一個家族就夠了。 一個具有實際字重範圍的優質無襯線字型,就能涵蓋展示、標題、內文與 UI。只有在第一個字型無法勝任特定角色時,才加入第二個家族:例如為行銷頁面加入一個有性格的展示用無襯線字型,或為程式碼與資料加入等寬字型。
- 僅限無襯線:無襯線且無斜體。 標題、內文、引言與圖說都使用直立無襯線字型。在網頁產品上,襯線標題或斜體行看起來就像模板戲服,即使在部落格、文件與奢華頁面上也應避免;應使用字重、大小與間距來傳達語氣。
- 除等寬字型外,最多兩個家族。 第三個文字家族會顯得猶豫不決。
- 根據主題選擇,而非習慣。 不要每個專案都用同一種字體。詢問產品在印刷或硬體上看起來像什麼,然後選擇具有該特質的字體:
| 產品感覺像 | 可選用 | 免費範例 |
|---|---|---|
| 精確工具(開發工具、資料、基礎設施) | 緊湊的 grotesk,資料用等寬字 | Geist, Switzer, Onest; Geist Mono, JetBrains Mono |
| 沉穩的金融或健康(金融、保險、診所) | 穩定的 neo-grotesk 或 humanist 無襯線字 | Inter, Public Sans, Source Sans 3 |
| 友善的消費性產品(社群、美食、旅遊、教育) | 較圓潤的 geometric 或 humanist 無襯線字 | Plus Jakarta Sans, Figtree, Nunito Sans, DM Sans |
| 自信的品牌或新創行銷頁面 | 在展示尺寸下有個性的無襯線字 | General Sans, Manrope, Bricolage Grotesque, Space Grotesk |
| 閱讀與出版(文件、部落格、雜誌) | 具有真實文字剪裁的沉穩無襯線字,同一家族內使用緊湊標題 | Inter, Satoshi, Source Sans 3 |
| 時尚、編輯或奢華 | 精緻的展示用無襯線字,設定為大且緊湊,僅用於標題 | Satoshi, General Sans, Clash Grotesk |
- 檢查字體能否勝任工作: 你需要的字重(通常是 400, 500, 600)、表格數字、良好的標點符號、你出貨的語言,以及如果你使用多種字重,則需要變數版本。
2. 定義角色,而非大小
以工作職責來命名文字。元件使用角色名稱;只有角色定義包含像素值。七個角色幾乎能涵蓋所有介面:
| 角色 | 用途 | 行銷頁面 | App UI |
|---|---|---|---|
display | 頁面主標題,每頁一個 | 48 至 80px,字重 600,行高 0.95 至 1.05,字距 -0.03em 至 -0.04em | 少用 |
title | 頁面與區段標題 | 32 至 44px,字重 600,行高 1.1,字距 -0.02em | 20 至 24px,字重 600,行高 1.25,字距 -0.01em |
heading | 卡片、面板與子區段標題 | 20 至 24px,字重 600,行高 1.25,字距 -0.01em | 15 至 16px,字重 600,行高 1.4 |
body | 段落 | 16 至 18px,字重 400,行高 1.55 至 1.65 | 14 至 15px,字重 400,行高 1.5 |
label | 按鈕、輸入欄位、導航、表格標題 | 14 至 15px,字重 500,行高 1.3 | 13 至 14px,字重 500,行高 1.3 |
caption | 輔助文字、後設資料、時間戳記 | 13 至 14px,字重 400,行高 1.45 | 12 至 13px,字重 400,行高 1.4 |
code | 行內程式碼、程式碼區塊、ID | 周圍文字的 0.9em,等寬字 | 相同 |
階層規則:
- 階層必須明顯。 相鄰角色在大小上至少相差約 20%,或是一個大小階層加上一個字重階層(14px 500 的 label 放在 13px 400 的 caption 上面可以;但 15px 400 與 16px 400 做不同工作則不行)。
- 比例有幫助,但表格為準。 行銷頁面適合 1.25 到 1.333 的比例;密集的 App UI 適合 1.125 到 1.2。四捨五入到整數像素。
- 最多三種字重: 一般(400)、中等(500)用於標籤、半粗(600)用於標題與展示。階層感也來自大小、顏色與空間,所以不需要五種字重。如果 600 在大尺寸展示行上看起來太重,請使用 500 作為展示字重,而不是增加第四種字重。
- 僅在行銷頁面上對 display 與 title 使用流體大小:
font-size: clamp(2.5rem, 1.5rem + 4vw, 5rem)。保持內文與 UI 文字固定,以便密集的版面保持可預測。 - 內文基線: 行銷與閱讀頁面為 16px,密集的 App UI 為 14px。行動裝置上輸入文字為 16px,否則 iOS Safari 會在聚焦欄位時放大頁面。
在 Tailwind CSS v4 中,一次性定義角色(將字型家族名稱替換為你選擇的):
@theme {
--text-display: clamp(2.75rem, 1.6rem + 4.2vw, 5rem);
--text-display--line-height: 1;
--text-display--letter-spacing: -0.035em;
--text-display--font-weight: 600;
--text-title: 2.25rem;
--text-title--line-height: 1.1;
--text-title--letter-spacing: -0.02em;
--text-title--font-weight: 600;
--text-heading: 1.25rem;
--text-heading--line-height: 1.3;
--text-heading--letter-spacing: -0.01em;
--text-heading--font-weight: 600;
--text-body: 1rem;
--text-body--line-height: 1.6;
--text-label: 0.875rem;
--text-label--line-height: 1.3;
--text-label--font-weight: 500;
--text-caption: 0.8125rem;
--text-caption--line-height: 1.45;
}
然後在標記中使用 text-display、text-title、text-body,而不是 text-[44px] 或一長串的 text-4xl leading-tight tracking-tight。在 Tailwind v3 中,將相同的值放在 theme.extend.fontSize 下,作為 [size, { lineHeight, letterSpacing, fontWeight }] 元組。
3. 行高與字距
- 行高隨著字型大小增加而減少。 Display 0.95 至 1.05,titles 1.1 至 1.2,body 1.5 至 1.65,labels 1.2 至 1.35。一個 64px 的標題若行高為 1.5,會散成獨立的行。
- 大字緊湊字距,內文無字距。 Display -0.03em 至 -0.04em,titles -0.02em,headings -0.01em,body 與 labels 為 0。不要緊於 -0.05em;字母會開始碰觸。根據你選擇的字體用肉眼調整。
- 小寫內文與介面文字無正字距。 正字距只對全大寫文字有幫助,而全大寫文字應該少見(見第 6 節)。
- 寬行需要更多行距。 如果內文接近 75 個字符,請使用行高 1.6 或更高;在 50 個字符時,1.5 就夠了。
- 淺色文字在深色背景上看起來更重且更緊。 在深色主題中,將內文行高大約增加 0.05。
4. 行長與斷行
- 內文:每行 60 到 75 個字符。 在段落上設定
max-width: 65ch,而不是在整個頁面上。圖說與輔助文字可以更窄。 - 展示標題:每行大約 12 到 20 個字符。 一個橫跨 1440px 螢幕的標題只有一行就沒有形狀。使用
max-width(以ch為單位)或容器寬度來限制它。 - 平衡標題,美化段落換行:
h1, h2, h3, .text-display, .text-title { text-wrap: balance; }
p, li, figcaption { text-wrap: pretty; }
兩者都是漸進增強:舊版瀏覽器會忽略它們。balance 會平均分配標題行的長度;pretty 會防止段落最後一行只有一個詞。
- 僅在片語之間手動斷行,並在文字渲染的所有寬度下檢查。一個在手機上落在行中間的
<br>比預設換行更糟。優先使用max-width而不是<br>。 - 長詞與 URL 在使用者內容中需要在其容器上設定
overflow-wrap: anywhere,否則它們會在行動裝置上將版面推向側邊。 - 截斷是最後手段。 在緊湊的 UI 中截斷單行標籤(Tailwind 中的
truncate)。如果隱藏的部分很重要,請讓完整文字可透過鍵盤和觸控存取(可聚焦元素上的工具提示、可展開的列、詳細檢視);僅有title屬性是不夠的。永遠不要截斷使用者必須閱讀才能操作的內文或任何內容。 - 多行截斷(
line-clamp-2):保持被截斷文字的行高在 1.3 或以上,以便下伸部(g, y, p)不會被切斷。不要在截斷內部添加底部內距;它會顯示下一行的頂部。
5. 文字顏色與對比
- 三種文字顏色就夠了: 主要(標題與內文)、次要(輔助文字、圖說、佔位文字)與停用。將它們定義為 token。避免透過動態降低不透明度來製作第四種。
- 對比度底線(WCAG 2.2 AA): 內文與小文字為 4.5:1,24px 及以上的文字(或 18.66px 粗體)為 3:1。次要文字和佔位文字也需要 4.5:1。只有停用控制項中的文字可以豁免。
- 在深色背景上使用近白色,而非純白色,用於長篇文字(大約 90% 到 94% 亮度)。純白色在近黑色上會刺眼。
- 在彩色或著色表面上, 將次要文字色調向表面色相傾斜,而不是使用中性灰,後者在顏色上看起來很髒。
6. 應避免的事項
- 眉毛與前導文字: 在標題上方的小號全大寫字母間距標籤("FEATURES", "WHY US", "HOW IT WORKS")。不要使用它們。它們是模板 UI 最明顯的標誌。如果標題需要上下文,請寫一個更好的標題。
- 一般來說,全大寫標籤, 包括側邊欄、設定面板、卡片、頁尾和示範控制項中的小節標題。句子大小寫閱讀速度更快;給小標題字重(500 或 600)和次要文字顏色。將全大寫保留給真正的縮寫(API, URL)。
- 漸層文字和標題中的一個彩色詞。 強調來自大小、字重與位置,而不是塗料。
- 斜體,隨處可見。 使用字重表示強調,並將引言設定為直立,旁邊加上規則或更大的尺寸。
- 襯線字型。 展示用襯線和文字用襯線在網頁產品上看起來都像戲服。請改用有個性的無襯線字型。
- 將等寬字型用作裝飾。 等寬字型用於程式碼、資料、ID、按鍵和欄位中的數字。行銷頁面上的等寬標籤是一種戲服。
- 超過兩行的置中段落。 僅置中短標題和單行 CTA。
- 在網路上使用左右對齊文字。 沒有連字符號會產生白河。
- 除連結外,對任何東西使用底線。
7. 數字、程式碼與資料
- 任何需要對齊或更新的事物中使用表格數字: 表格、價格、計時器、計數器、統計資料。
font-variant-numeric: tabular-nums;(Tailwindtabular-nums)。沒有它,計數數字會因為數字寬度變化而橫向抖動。 - 帶斜線的零 用於可能混淆 0 和 O 的 ID 和代碼:
font-variant-numeric: tabular-nums slashed-zero;。 - 將數字對齊在表格儲存格末端(
text-align: end),以便小數點對齊。文字欄對齊在開頭。 - 程式碼: 等寬字型,大小約為周圍文字的 0.9em,以便其 x 高度匹配。行內程式碼獲得淡色背景和 0.2em 水平內距,無邊框。程式碼區塊獲得約 1.6 的行高和水平捲動,永遠不要使用會破壞縮排的換行。
- 按鍵(
<kbd>)使用 caption 大小的等寬字型。
8. 連結
在連續文字中為連結加底線;僅靠顏色對色盲讀者來說是不夠的。將其範圍限定在散文,以便導覽列表和按鈕不會有底線(.prose 是任何包裹你的文章或長篇內容的元素):
:where(p, td, dd, figcaption, blockquote) a,
:where(.prose, article) li a {
text-decoration-line: underline;
text-decoration-thickness: 1px;
text-underline-offset: 0.2em;
}
導覽、按鈕和卡片連結不需要底線;它們的位置已經說明它們是可互動的。
9. 載入字型而不造成版面位移
- Next.js: 使用
next/font(next/font/google或next/font/local)。它會自行託管、預載入並產生具有匹配度量標準的後備字型,因此頁面在字型到達時不會跳動。將其公開為 CSS 變數,並使用@theme inline將主題字型映射到它(以便在使用處讀取變數,而不是在:root處解析一次):
// app/layout.tsx
import { Onest } from "next/font/google";
const sans = Onest({ subsets: ["latin"], variable: "--font-brand", display: "swap" });
// <html lang="en" className={sans.variable}>
@theme inline {
--font-sans: var(--font-brand), ui-sans-serif, system-ui, sans-serif;
}
- 光學尺寸: 具有
opsz軸的字體(Inter, Roboto Flex, Fraunces)只有在載入時才會獲得該軸:Inter({ subsets: ["latin"], axes: ["opsz"] })。保持font-optical-sizing: auto,以便小文字獲得更堅固的剪裁,大文字獲得更精緻的剪裁。 - 其他情況: 自行託管 WOFF2,
font-display: swap,僅預載入折疊上方使用的一或兩個檔案,並在本地後備字型上設定size-adjust、ascent-override和descent-override,以便交換不會造成版面位移。 - 僅載入你使用的部分。 偏好一個變數字型檔案而不是六個靜態字重。子集化到你出貨的腳本。
10. 渲染細節
- 在深色主題上,
-webkit-font-smoothing: antialiased可以讓 macOS 上的淺色文字看起來不那麼腫脹。淺色主題保持預設值。 - 將
::selection設定為品牌色調並保持可讀性。瀏覽器預設的藍色是頁面未完成的跡象。 - 在文案中使用真正的標點符號:彎引號(“ ” ‘ ’)、省略號字元(…)和尺寸中的乘號(×)。
- 尊重使用者設定:以
rem為單位設定文字大小,永遠不要阻止縮放,並檢查文字在 200% 文字大小以及較大的字母和行間距時是否仍然合適。
11. 完成前檢查
- 每個文字樣式都來自已命名的角色;沒有雜散的像素大小。
- 相鄰角色在大小或大小加上字重上明顯不同。
- 最多兩個家族加上等寬字型,最多三種字重,全部已載入。
- 內文 16px(密集 UI 14px),行動裝置上輸入欄位 16px。
- 段落限制在大約 65ch;展示行大約 12 到 20 個字符。
- 標題已平衡,段落已美化換行。
- 沒有眉毛標題、沒有漸層文字、沒有全大寫標籤、沒有斜體、沒有襯線。
- 數值對比度符合 AA 標準;深色主題使用近白色。
- 數字使用表格數字,程式碼使用等寬字型。
- 字型已使用
next/font或等效方法載入,不會造成版面位移。 - 選取範圍樣式已設定。