用 12 行 CSS 复现 Claude 的回答排版
2026-05-08 · 排版笔记
上周我做了一件挺无聊但挺爽的事:打开 claude.ai, 让它输出一段含完整 Markdown 元素的回答,然后用 DevTools 把每一个标签的 computed style 抓下来,写成一份 ~280 行的 CSS。这篇博客就是用那份 CSS 渲染的 —— 你看到的字号、行距、列表缩进、引用块边线,每一个数值都是从 Claude 的真实 DOM 里 1:1 拷贝出来的。
TL;DR:Claude 的排版没有任何"花活",但它在 4 个细节上做得 非常克制 —— 标题字重 600 而非 700、标题与下方段落收紧 4px、列表项之间用 flex gap 控制间距、行内代码用半透明灰底 + 暗红字。 这 4 件小事加起来,就是一种"安静、易读"的气质。
1. 颜色:克制到几乎察觉不到
Claude 的正文色是 rgb(18, 18, 18),几乎是纯黑但又差那么一点点。 引用块的文字色是 rgb(55, 55, 52),比正文淡一档。所有边线都是带 透明度的 rgba(31, 31, 30, X),X 在 0.1 ~ 0.6 之间浮动。
整理成 design token 后是这样的:
:root {
--md-text: rgb(18, 18, 18);
--md-text-muted: rgb(55, 55, 52);
--md-text-code: rgb(141, 37, 37); /* 行内代码暗红 */
--md-border-soft: rgba(31, 31, 30, 0.15);
--md-bg-pre: rgba(255, 255, 255, 0.5);
}1.1 为什么行内代码用暗红?
实测 rgb(141, 37, 37) 在浅米色背景上的对比度是 6.8:1,刚好越过 WCAG AA 的门槛;而它比纯黑多了一点"温度",又不像鲜红那么刺眼。Claude 显然在 这件事上调过很多次。
2. 间距:标题"贴"段落,列表"贴"列表
最反直觉的一件事:Claude 把所有标题的 margin-bottom 设成了 -4px。负值。意思是标题会主动"吃掉"一点和下方段落之间的空白:
- 顶层块之间的间距用容器的
gap: 12px统一控制; - 标题是顶层块的特例,它要"咬住"自己介绍的那段文字,所以补 -4px;
- 列表项之间用
flex-direction: column; gap: 4px, 而不是li自身的 margin —— 这样嵌套列表收紧到 0 也很自然。- 嵌套
ul的margin-top: 4px; - 嵌套
ul的margin-bottom: 0; - 非末位嵌套块补
padding-bottom: 4px,避免和下一个兄弟挤在一起。
- 嵌套
这套间距规则放在一起,就形成了 Claude 那种"密但不挤"的节奏。
3. 字体:衬线优先,CJK 自适应
Claude 用的是它自家定制的 Anthropic Serif,本地没有的话会 fallback 到 Georgia → 各种 CJK 字体。完整的 fallback 链长这样:
font-family:
"Anthropic Serif",
Georgia,
"Arial Hebrew", "Noto Sans Hebrew",
"Times New Roman", Times,
"Hiragino Sans", "Yu Gothic", Meiryo,
"Noto Sans CJK JP",
"PingFang TC", "Microsoft JhengHei",
"PingFang SC", "Microsoft YaHei",
"Apple SD Gothic Neo", "Malgun Gothic",
serif;注意到没有 —— 它把 希伯来语排在 CJK 前面。理论依据是 希伯来字母在 Georgia 里的渲染质量比较差,要尽早 fallback 到原生字体。
4. 实测尺寸表
下面是我从 DevTools 抓出来的最终数值,已经写进 CSS 里:
| 元素 | font-size | line-height | 备注 |
|---|---|---|---|
正文 p | 16px | 1.5(24px) | 容器 gap 12px |
h2 | 22px | 1.2(26.4px) | weight 600,mt 0 |
h3 | 18px | 1.467(26.4px) | weight 600,mt 12 |
code(行内) | 0.9em(相对父) | 继承 | 暗红 + 半透明灰底 |
pre | 14px | 1.625(22.75px) | 白底半透明 + 0.5px 边 |
table | 14px | 1.7(23.8px) | 表头底边粗于行 |
5. 一些被我"修正"了的小细节
原始计算样式里有一些显然是工程脚手架副作用的、不该出现在"设计意图"里的值。 我在还原时偷偷修掉了:
li margin-bottom: 8px—— 实际是被 flex gap 覆盖的死代码,删掉;blockquote padding-right: 32px—— 看起来像在留侧栏,但 Claude 的 对话区根本没侧栏,估计是历史遗留;这里保留了,可能某天它真的要用;table 单元格 padding-left: 1px—— 不是我打错字,真的是 1px。 Claude 故意让数据列贴最左侧,让眼睛能直接顺着列首扫。
试试看链接和强调
选一段混合文本来压力测试:这是 加粗,这是 斜体, 这是 划掉的话,这是 外链, 还有 加粗 + 斜体,以及紧贴的 inline_code()。整体节奏应该不打架。
更深一级的标题(h4)
到 h4 就基本和正文同号(16px)了,靠的是字重 600 和 8px 的上间距与正文区分。 再深就没必要了 —— 一个对话回答里出现 h5、h6 几乎是写作味道出了问题。
结语
排版这件事的有趣之处在于:你看着像"什么都没做",但每一个选择背后都有理由。 如果你也在做 LLM 的对话 UI,建议从 Claude、ChatGPT、Gemini 各扒一份这样的 CSS 出来对照看 —— 你会发现三家在同一个问题(标题与段落怎么连)上给出的答案 非常不一样。
—— 完 ——