替 blog 找設計詞彙:從 Vuetify 到 Magazine 風的一次設計診斷
我這個 blog 改版想做很久了。每次打開自己的站,都覺得「不對」,但說不出哪裡不對。看別人的 blog ──Josh Comeau、Robin Rendle、那些做得好的個人站 ──就知道差在哪一個層級的東西,但翻不出名字。
這篇是替自己補課的紀錄。把這次從 Vuetify1 換到 UnoCSS2 + Magazine 風的過程,整理成一個診斷 + 三個詞彙。詞彙的目的不是裝逼,是讓下次再感覺「不對」的時候,能指著問題的地方說「就是這個」。
如果你也有「明明會寫 code、會選色票、會抄 Figma,但自己做出來的東西就是少一口氣」的感覺,這篇是寫給你的。
診斷:Tool vs Goal Mismatch
Vuetify 沒有做錯什麼,是我把它放錯地方了。
Vuetify 是一套以 Material Design3 為基礎的 Vue component library。它的設計目標非常清楚:讓你能快速做出功能密集的應用程式介面。Dashboard、admin、CRM、SaaS 工具 ── 一個畫面要塞 100 個 component 都還能活下去的場景。
要做到這件事,Material Design 在底層解決的是這些問題:
- Affordance:使用者要一眼看出「哪裡可以點」。所以 button 有陰影、card 有 elevation、chip 有填色膠囊形狀。
- 密度:資訊量要大、操作要密,所以間距 token 設得緊、字級壓縮在小範圍內。
- 可發現性:功能要被找到,所以視覺權重平均分配 ── 沒有單一元素特別搶戲。
Blog 的目標剛好相反。Blog 要做的事只有一件:讓人停下來讀一段話。
而要讓人停下來讀,需要的是:
- 節奏:標題、段落、引言之間要有明顯的呼吸頓挫
- 留白:眼睛要有地方休息,不能塞滿
- 層級戲劇:一篇文章的 H1 必須壓制其他元素,讓讀者知道「故事從這裡開始」
把 Vuetify 套在 blog 上,就是用「能讓 100 個 component 活下去」的設計系統,去做一件「需要讓 1 段話呼吸」的事。整齊、乾淨、但平。沒有一個地方做錯,但整體就是「不對」。
這個錯位有名字 ── 我把它叫做 tool-vs-goal mismatch。工具本身沒問題,但工具要解的問題跟你要解的問題不是同一個。
第一個詞彙:tool-vs-goal mismatch。下次選 framework 之前,先問「這個工具預設要解的問題,跟我要解的問題一致嗎?」
第一招:Type Scale 的戲劇對比
editorial / magazine 風的張力來自哪裡?很多人第一直覺是「配色」。錯了。是字級。
Vuetify 的 typography token 是這樣設計的:text-h1 到 text-body-1 之間,倍率大約落在 1.25–1.5x。這個倍率區間在 app UI 場景非常合理 ── 你不希望某個元素特別搶戲,因為畫面上每個 component 都要被看到。
但在 blog,這個倍率讓整頁字看起來「同等重要」。沒有戲。

新版的 type scale 直接拉到 4x 以上:
/* Magazine type scale */
--font-display: clamp(2.25rem, 6vw, 4rem); /* line-height: 1.05 */
--font-h-article: clamp(2rem, 4vw, 3rem); /* line-height: 1.10 */
--font-h2: 2.125rem; /* line-height: 1.20 */
--font-h3: 1.625rem; /* line-height: 1.30 */
--font-body: 1.125rem; /* line-height: 1.75 */
--font-meta: 0.875rem; /* uppercase, tracking-wider */
兩個關鍵設定:
clamp()讓大字級隨視窗寬度伸縮,桌機展現戲劇感、手機自動收回不爆版- 大字級 line-height 壓到 1.05–1.10、body 卻拉到 1.75 ── 反差越大越「印刷」
這套 scale 的精神可以從 Refactoring UI4 借一句話:「If you want to make something look beautiful, make it large or make it small ── never make it medium.」 Vuetify 的問題就是所有東西都 medium。

第二個詞彙:type scale drama。editorial 設計的張力來自字級的戲劇對比,不是配色。倍率拉不開,配再多顏色都救不回來。
第二招:Typographic Marker 取代色階
字級拉開之後,下一個問題:meta 資訊(tag、日期、reading time)要怎麼區分?
我的第一直覺是「加顏色」── 用一個 muted 灰、或一個低彩度的 accent 來標。但做 PostCard 的時候踩到一個有意思的決策。
當時 PostCard 的 tag 區塊原本是 Vuetify 的 v-chip:彩色填底膠囊、視覺權重很重。我想換成 plain text,加 # prefix 做身份提示。同時想把字色從 muted 拉回正常文字色 ── 直覺覺得這樣「更乾淨」。
結果發現 ── # 做完身份提示的工,色階就不該再加上去。

理由是:editorial minimal 的視覺邏輯是 ── 用 typographic marker(符號、字距、italic、uppercase)做身份/分類的線索;色階則保留給真正的視覺層級(標題 vs meta vs body)。
# 已經是一個 typographic marker。它告訴讀者「這是一個 tag」。如果我同時把字色拉到正常文字色,就等於在同一個 meta 區塊內又加上一層「色階對比」。結果是 meta 區塊內部開始打架、搶走標題的主角地位。
最後決定:# 加上去、色調維持 muted。

這個原則可以推廣到整個 blog:
| 場景 | typographic marker | 不要再加 |
|---|---|---|
| Tag | # prefix | 色階對比 |
| 日期 | uppercase + tracking-wider | 強色 |
| Reading time | · separator | bold |
| TOC item | indent + small caps | 邊框、底色 |
| Archive 年份 | 大字級 + serif | 色塊 |
色階是稀缺資源。一個畫面能用的「強色階對比」其實只有 2–3 階:標題 vs body、body vs muted、accent(link/blockquote)。把這個額度浪費在 meta 區塊內部分強弱,就會發現要「凸顯標題」的時候已經沒額度了。
第三個詞彙:typographic marker。需要「告訴讀者這是什麼」用符號/字距/italic;需要「建立真正的層級對比」才動色階。不要在同一個區塊內同時用兩種。
第三招:奶油紙底 + 一個 accent
最後一個是底色跟 accent 的決策。
舊版用 Vuetify 預設的純白底 #FFFFFF + Material 預設藍紫色系。新版改成:
:root {
--color-bg: #FAF8F3; /* 奶油紙感 */
--color-surface: #FFFFFF;
--color-text: #1A1A1A;
--color-muted: #6B6B6B;
--color-accent: #B23A2F; /* 磚紅,只給 link / blockquote 左線 */
--color-border: #E6E1D6;
}
兩個決策值得拆開講。
為什麼不是純白
純白 #FFFFFF 在 content-first 場景太冷、太「web app」。它會讓字看起來像「螢幕上顯示的字」,而不是「印刷在紙上的字」。
奶油紙底 #FAF8F3 是一個非常輕微的暖色偏移 ── HSL 約 hsl(40, 33%, 97%),肉眼幾乎看不出黃,但字落上去的感覺完全不同。它把「螢幕」這件事退到背景,把「文字」推到前景。
這是純粹氛圍的選擇,沒有功能上的理由。但氛圍就是 editorial 設計的功能本身。
為什麼 accent 只用一個、只給兩個地方
磚紅 #B23A2F 是整個 blog 唯一的 accent。它只出現在兩個地方:
- 文章內的 inline link
- blockquote 的左側細線
理由是:accent 一旦變裝飾,就喪失了 signal 功能。
如果磚紅同時出現在 button、tag、icon、navigation hover、sidebar 強調、reading time 圈圈、social media icon ── 它就變成「這個 blog 的點綴色」,而不是「這個位置有重要資訊」的訊號。讀者掃過去的時候,眼睛不再停留。
把 accent 用得越省,每一次出現的訊號強度就越強。看到磚紅 → 知道是 link、知道是引言。signal vs noise 的取捨。


字體:Fraunces 為什麼撐得住
順帶提一句 ── 這套色票需要對的字體才撐得起來。我選了 Fraunces5 當標題 serif,繁中 fallback 到 Noto Serif TC。
Fraunces 是 variable font(可變字軸),支援 optical size:字級越大、字形的細節(serif 末端、curve 曲率)會自動增加;字級越小、字形自動簡化。也就是說,display 級別跟 H3 級別用同一個字體檔,但長得不一樣。
這跟 type scale drama 是一組的:字級拉得越大、字形也跟著「變得更值得被看」。
第四個詞彙:signal vs noise。底色定氣質,accent 越省越有力。一個畫面只給 accent 一個工作。
把詞彙交回給你
整理一下這次補課拿到的四個詞彙:
- Tool-vs-goal mismatch ── 選工具之前先確認工具預設要解的問題,跟你要解的問題一致
- Type scale drama ── editorial 的張力來自字級倍率,不是配色;倍率拉不開,配色救不回來
- Typographic marker ── 身份提示用符號/字距/italic;色階只留給真正的層級對比;不要同一區塊內疊兩種
- Signal vs noise ── accent 越省越有力;一個畫面只給 accent 一個工作
這四個詞彙不是設計法則,是幫助你下次「感覺不對」的時候能指出來的工具。能命名的問題就能討論、能討論的問題就能改。卡住的時候不是品味的問題 ── 是缺詞彙。
下兩篇會分別記:
- 工程篇:為什麼這次改版要拆 Phase A / Phase B、不能一次做完
- Bug war story:Nuxt 3.21 的
payloadExtraction對中文 URL prerender 的隱性 500 ── 一個花了幾小時才抓到的坑
環境資訊
- Nuxt 3.21
- UnoCSS 0.x(取代 Vuetify 3.5)
@nuxtjs/color-mode3.x- Fraunces / Noto Serif TC(標題 serif)
- Inter / Noto Sans TC(內文)
- JetBrains Mono(code)
Reference
- Vuetify 官方站,Material Design Vue component framework:https://vuetifyjs.com/ ↩
- UnoCSS 官方站,instant on-demand atomic CSS engine:https://unocss.dev/ ↩
- Material Design 3 設計目標與基礎概念:https://m3.material.io/foundations ↩
- Refactoring UI(Adam Wathan、Steve Schoger)── 字級對比與視覺層級的常被引用來源:https://www.refactoringui.com/ ↩
- Fraunces ── 由 Undercase Type 設計的 variable serif,支援 optical size:https://fonts.google.com/specimen/Fraunces ↩