|
|
@@ -0,0 +1,260 @@
|
|
|
+# Typography:排印推理系统
|
|
|
+
|
|
|
+> **这不是字体清单,是配对与排版的推理规则。** `design-styles.md` 已经给了 40 种风格各自的字体名;本文回答的是「为什么这样配」「拿到任意内容怎么推导出字号/行长/字重」。目标:同一个风格标签,落到不同内容上,能推导出不同的排印结果,而不是每次都抄同一套字号。
|
|
|
+>
|
|
|
+> 前置纪律不变:有 design context 先 lift 用户自己的字体(见 `design-context.md`),本文的一切只在「用户没有字体规范」时启用。
|
|
|
+
|
|
|
+## 0. 排印决策顺序
|
|
|
+
|
|
|
+拿到内容后按这个顺序推,每一步都由上一步决定,不许跳到「直接选个好看的字体」:
|
|
|
+
|
|
|
+1. **内容类型** → 长文阅读 / 数据密集 / 营销大字 / UI 界面,决定音阶比例和正文字号
|
|
|
+2. **语言构成** → 纯中文 / 中西混排 / 纯西文,决定 fallback 链写法和行高基准
|
|
|
+3. **风格温度**(对齐 `design-styles.md` 的安静/中性/大胆三档)→ 决定字体配对的对比度来源
|
|
|
+4. **最后才是字体名** → 从下面第 3 章配对表选,或从风格库对应条目取
|
|
|
+
|
|
|
+为什么:先选字体名的做法,会让「内容是什么」对排印零影响,这正是千人一面的病根。
|
|
|
+
|
|
|
+## 1. 字号音阶(modular scale)
|
|
|
+
|
|
|
+字号不是拍脑袋,是从正文字号乘一个固定比例逐级推出来的。比例决定页面的「戏剧性」:
|
|
|
+
|
|
|
+| 比例 | 名字 | 性格 | 适用 |
|
|
|
+|------|------|------|------|
|
|
|
+| 1.2 | 小三度 | 平缓、层级多而不吵 | dashboard、文档站、信息密集 UI |
|
|
|
+| 1.25 | 大三度 | 通用、安全 | 大多数网页、产品落地页 |
|
|
|
+| 1.333 | 纯四度 | 标题明显跳出 | editorial 长文、营销页、报告 |
|
|
|
+| 1.5 | 纯五度 | 戏剧性、层级极少 | 大字报、slides、hero 一屏一句 |
|
|
|
+
|
|
|
+**推导规则**:正文定 16-18px(中文正文建议 17-18px,汉字笔画密、同字号比西文显挤),然后按比例上推标题、下推 caption。层级超过 5 档就是失控,砍掉。
|
|
|
+
|
|
|
+| 档位 | 1.25 比例下的参考值 | 用途 |
|
|
|
+|------|--------------------|------|
|
|
|
+| caption | 12-13px | 图注、meta 信息、EXIF 式小字 |
|
|
|
+| small | 14px | 辅助说明、表格 |
|
|
|
+| body | 16-18px | 正文,一切的基准 |
|
|
|
+| h3 | ≈1.25x | 小节标题 |
|
|
|
+| h2 | ≈1.56x | 章节标题 |
|
|
|
+| h1 | ≈1.95x | 页面标题 |
|
|
|
+| display | 3x-8x,脱离音阶自由发挥 | hero 巨字,由版面而非音阶决定 |
|
|
|
+
|
|
|
+**流式字号写法**(display 档必用,避免大屏死板小屏溢出):
|
|
|
+
|
|
|
+```css
|
|
|
+/* clamp(最小值, 首选值, 最大值):首选值 = 基础rem + 视口系数 */
|
|
|
+h1 { font-size: clamp(2rem, 1.2rem + 3.5vw, 4.5rem); }
|
|
|
+.display { font-size: clamp(3rem, 1rem + 9vw, 9rem); }
|
|
|
+/* 正文不要 clamp 出大幅波动,16→18 的窄区间即可 */
|
|
|
+body { font-size: clamp(1rem, 0.95rem + 0.3vw, 1.125rem); }
|
|
|
+```
|
|
|
+
|
|
|
+为什么 display 脱离音阶:hero 巨字是版面元素不是文本层级,它的尺寸由「占视口几成」决定,用 vw 推导比用音阶推导更合理。
|
|
|
+
|
|
|
+## 2. 行长与行高
|
|
|
+
|
|
|
+### 行长(比字体选择更影响可读性)
|
|
|
+
|
|
|
+| 语言 | 舒适区 | CSS 实现 |
|
|
|
+|------|--------|----------|
|
|
|
+| 西文正文 | 45-75 字符,最佳 66 | `max-width: 65ch` |
|
|
|
+| 中文正文 | 一行 22-38 字,最佳 28-32 字 | `max-width: 36em`(em 随字号缩放) |
|
|
|
+| 图注/侧栏 | 更短,中文 15-20 字 | 窄容器天然限制 |
|
|
|
+
|
|
|
+为什么中文更短:汉字是无空格的致密方块字,同宽度下承载的信息量明显高于西文,同样的眼跳次数中文读进更多内容,行太长回行时找不到下一行开头。
|
|
|
+
|
|
|
+### 行高随行长联动
|
|
|
+
|
|
|
+行高不是常数,是行长的函数。行越长,眼睛回行距离越远,需要更大的行间距当「轨道」:
|
|
|
+
|
|
|
+| 场景 | 西文 | 中文 |
|
|
|
+|------|------|------|
|
|
|
+| display 大字(1-2 行) | 0.95-1.1 | 1.1-1.25 |
|
|
|
+| 标题(h1-h3) | 1.1-1.3 | 1.3-1.4 |
|
|
|
+| 短行正文(<30 字/行) | 1.4-1.5 | 1.6-1.7 |
|
|
|
+| 长行正文(接近上限) | 1.6 | 1.8-2.0 |
|
|
|
+
|
|
|
+中文全线比西文高 0.2 左右:汉字是满格方块,没有西文小写字母之间的天然空隙,行距不足会糊成一片。
|
|
|
+
|
|
|
+### text-wrap(2024+ 浏览器都支持了,白拿的排印质量)
|
|
|
+
|
|
|
+```css
|
|
|
+h1, h2, h3 { text-wrap: balance; } /* 标题多行时各行长度均衡,消灭孤字行 */
|
|
|
+p { text-wrap: pretty; } /* 正文消灭行尾孤词(西文效果明显,中文轻微) */
|
|
|
+```
|
|
|
+
|
|
|
+balance 只用于 ≤4 行的标题(算法限制 6 行且有性能成本);pretty 全局给正文无副作用。
|
|
|
+
|
|
|
+## 3. 十组开源字体配对(西文)
|
|
|
+
|
|
|
+配对的三种对比度来源,配之前先想清楚用哪种:
|
|
|
+
|
|
|
+- **形式对比**:衬线 display x 无衬线 body(最经典,但要 x-height 咬合,否则视觉字号跳)
|
|
|
+- **同族咬合**:superfamily 同一设计骨架(零风险,代价是平淡)
|
|
|
+- **时代对比**:古典字形 x 现代字形(谱系差 200 年以上才有张力,差 50 年只显得乱)
|
|
|
+
|
|
|
+| # | 配对(display + body) | 配对逻辑 | 温度 | 获取 |
|
|
|
+|---|------------------------|----------|------|------|
|
|
|
+| 1 | Newsreader + Geist | 形式对比:屏显优化的过渡衬线,x-height 高、与 Geist 咬合好;**Fraunces 的正牌平替** | 安静 | Google Fonts / Vercel 官方仓库 |
|
|
|
+| 2 | Source Serif 4 + Source Sans 3 | 同族咬合:Adobe 同设计系统,字高字重节奏完全对齐,报告和文档零翻车 | 安静 | Google Fonts |
|
|
|
+| 3 | EB Garamond + IBM Plex Sans | 时代对比:16 世纪法国老衬线 x 2017 理性 grotesque,差 400 年的张力;注意 Garamond x-height 低,同行混用需字号补偿(+8% 是经验起点,系统解法用 `font-size-adjust`,见第 4 章) | 安静·文气 | Google Fonts |
|
|
|
+| 4 | Lora + Hanken Grotesk | 形式对比:Lora 笔刷感衬线中等反差,屏显耐看;Hanken 是 Söhne 气质的开源近亲 | 中性 | Google Fonts |
|
|
|
+| 5 | Instrument Serif + Geist | 形式对比:只有 400 一档字重,天生 display-only,正文必须交给 sans。⚠️ 正在被 AI 工具用烂的路上,2026 年慎用于「想显得独特」的场合 | 中性 | Google Fonts |
|
|
|
+| 6 | Schibsted Grotesk + Source Serif 4 | 反转结构:grotesque 当 display、衬线当正文,媒体感;**Space Grotesk 泛滥后的平替**(挪威 Schibsted 报业定制开源,带新闻血统) | 中性 | Google Fonts |
|
|
|
+| 7 | Bricolage Grotesque + Newsreader | 形式对比:Bricolage 的 ink trap 和不规则细节在大字号才显现,天生 display;配安静衬线正文形成粗野 x 文雅 | 大胆 | Google Fonts |
|
|
|
+| 8 | Archivo(Expanded/Black)+ Inter | 大字报结构:Archivo 宽体黑重压场,Inter 只当 14-16px 正文工蜂(这是 Inter 的正确用法,见反模式) | 大胆 | Google Fonts |
|
|
|
+| 9 | Cormorant Garamond + Work Sans | 高反差奢侈感:Cormorant 笔画极细,**必须 ≥40px 才成立**,小字号笔画会断;适合时尚/太空图录风 | 大胆 | Google Fonts |
|
|
|
+| 10 | Geist Mono / JetBrains Mono + Geist | 等宽当主角:命令行感、工程感;等宽只用于标签/编号/代码,整段正文用等宽是灾难(行长膨胀 30%) | 中性·技术 | Vercel / JetBrains 官方,均 OFL |
|
|
|
+
|
|
|
+**已被用烂名单**(AI 生成页面的指纹,用了等于自曝):
|
|
|
+
|
|
|
+| 烂大街 | 为什么烂 | 平替 |
|
|
|
+|--------|----------|------|
|
|
|
+| Fraunces 当 display | 2023-2025 所有 AI 设计工具的默认「有品位」选项 | Newsreader、Libre Caslon Text |
|
|
|
+| Inter 当 display | Inter 是为 UI 小字设计的,大字号下匀质无表情 | Archivo、Anton、Schibsted Grotesk |
|
|
|
+| Space Grotesk | 「科技感」的偷懒答案,泛滥于加密/AI 落地页 | Schibsted Grotesk、Familjen Grotesk |
|
|
|
+| Playfair Display | 「优雅」的偷懒答案,婚礼请柬既视感 | Cormorant(更极端)、DM Serif Display(更憨) |
|
|
|
+
|
|
|
+## 4. 中文排印(本文最重的一章)
|
|
|
+
|
|
|
+西文排印有百年成熟工具链,中文没有。AI 设计工具在中文上集体摆烂(默认交给系统字体、直接套西文规则),这里是差异化所在。
|
|
|
+
|
|
|
+### 4.1 开源/免费商用中文字体地图
|
|
|
+
|
|
|
+| 字体 | 类别 | 气质 | 温度 | 获取 |
|
|
|
+|------|------|------|------|------|
|
|
|
+| 思源宋体(Noto Serif SC) | 宋体 | 出版正统、7 字重齐全,Heavy 可当 display | 安静-中性 | Google Fonts,OFL |
|
|
|
+| 思源黑体(Noto Sans SC) | 黑体 | 中文界的 Inter:可靠、无表情,当默认正文没错但没个性 | 全温度兜底 | Google Fonts,OFL |
|
|
|
+| 霞鹜文楷 | 楷体 | 手写温度、亲切,适合文艺/教育/个人博客正文与引文 | 安静·暖 | GitHub lxgw/LxgwWenKai,OFL |
|
|
|
+| 霞鹜新晰黑 | 黑体 | 比思源黑更瘦更透气的屏显黑,正文久读不累 | 安静 | GitHub lxgw/LxgwNeoXiHei |
|
|
|
+| 得意黑 Smiley Sans | 斜黑体 | **中文世界罕见的原生斜体**,运动感、标题专用;正文用它会晕 | 大胆 | GitHub atelier-anchor/smiley-sans,OFL |
|
|
|
+| 汇文明朝体 | 旧字形明朝 | 老印刷铅字气、复古出版,适合书封/文化类 display | 中性-大胆·复古 | 猫啃网/GitHub,免费商用 |
|
|
|
+| 京华老宋体 | 老宋 | 笔画方硬的标题宋,报头感 | 大胆·复古 | 猫啃网,免费商用 |
|
|
|
+| 源流明体/源样明体 | 明朝体(繁向) | 思源宋改刻,保留传统字形细节,繁体内容首选 | 安静·古典 | GitHub ButTaiwan,OFL |
|
|
|
+| 未来荧黑 Glow Sans | 几何黑 | 思源黑衍生的现代几何黑,多宽度(Compressed 可做窄长 display) | 中性-大胆·现代 | GitHub welai/glow-sans,OFL |
|
|
|
+| MiSans / HarmonyOS Sans / OPPO Sans | 厂商 UI 黑 | 比思源黑略有性格的 UI 黑,App 原型合适 | 中性 | 各厂官网,免费商用 |
|
|
|
+
|
|
|
+选型推理:**正文只在宋/黑/楷里选**(其余都是 display 字体,整段用会累);display 想要个性时才去动得意黑/老宋/明朝体。中文字体一个顶西文十个(单文件 5-15MB),一页最多两个中文字体家族,为加载和统一性两个原因。
|
|
|
+
|
|
|
+### 4.2 中西混排规则
|
|
|
+
|
|
|
+**fallback 链是第一杠杆**:中文字体自带的西文字符普遍难看(思源黑的拉丁字母呆板),把西文字体放在前面,拉丁字符和数字被它接住,汉字自动落到后面的中文字体:
|
|
|
+
|
|
|
+```css
|
|
|
+/* 西文在前,中文在后,系统中文兜底,泛型收尾 */
|
|
|
+font-family: "Geist", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
|
|
|
+/* 衬线同理 */
|
|
|
+font-family: "Newsreader", "Noto Serif SC", "Songti SC", serif;
|
|
|
+```
|
|
|
+
|
|
|
+为什么这个顺序:font-family 是逐字符匹配的,西文字体不含 CJK 码位,汉字自然穿透到中文字体。反过来写(中文在前)西文字符全被中文字体吃掉,等于白配。
|
|
|
+
|
|
|
+**字号补偿**:同字号下西文小写视觉偏小(x-height 只占字身一半,汉字占满)。两种解法:
|
|
|
+
|
|
|
+```css
|
|
|
+/* 解法一:font-size-adjust 让 fallback 字体按 x-height 归一(Chrome 127+/FF/Safari 17+) */
|
|
|
+:root { font-size-adjust: from-font; }
|
|
|
+/* 解法二:选 x-height 高的西文体(Geist/Inter/Source Sans 都高),混排天然齐 */
|
|
|
+```
|
|
|
+
|
|
|
+**baseline 对齐**:中西 baseline 不一致时症状是英文单词在中文行里「下沉」。优先换 x-height 更高的西文体;个别 display 场景用 `vertical-align: -0.02em~-0.06em` 微调西文 span,正文别这么修(维护成本大于收益)。
|
|
|
+
|
|
|
+**数字规则**:数字一律走西文字体(fallback 链已保证),数据表格必须加 `font-variant-numeric: tabular-nums`,否则 1 和 8 宽度不同,列会抖。
|
|
|
+
|
|
|
+**中英之间不加空格**:这是本仓库规范(花叔明确不用盘古之白),靠 fallback 链的字体本身留白,不靠手动敲空格。
|
|
|
+
|
|
|
+### 4.3 中文没有斜体
|
|
|
+
|
|
|
+中文字形没有 italic 传统,浏览器遇到 `font-style: italic` 会机械倾斜汉字(faux italic),笔画变形、极丑。强调手段替换表:
|
|
|
+
|
|
|
+| 西文习惯 | 中文替代 | CSS |
|
|
|
+|----------|----------|-----|
|
|
|
+| italic 强调 | 换字重 | `font-weight: 600`(前提:字体真有这档字重) |
|
|
|
+| italic 书名/引用 | 底色高亮 | `background: linear-gradient(transparent 60%, #FFE9A8 60%)` 荧光笔式 |
|
|
|
+| italic 引文块 | 换字体 | 引文整段换霞鹜文楷,楷体本身就是中文的「引用语气」 |
|
|
|
+| italic 专名 | 颜色/着重号 | `text-emphasis: dot`(着重号,中文原生强调,支持度已可用) |
|
|
|
+
|
|
|
+保险丝:`font-synthesis: none;` 全局禁掉合成斜体和合成加粗,宁可不强调也不接受变形字。
|
|
|
+
|
|
|
+### 4.4 标点规范
|
|
|
+
|
|
|
+| 规则 | 做法 | 为什么 |
|
|
|
+|------|------|--------|
|
|
|
+| 引号 | 直角引号「」『』,不用弯引号 "" | 弯引号在中文字体里是全角占位但形状是西文的,视觉漂浮;「」是本仓库硬规范 |
|
|
|
+| 避头尾 | `line-break: strict;` | 禁止句号逗号出现在行首、开引号出现在行尾,这是中文排版的底线 |
|
|
|
+| 标点悬挂 | `hanging-punctuation: first allow-end;`(仅 Safari);跨浏览器用 `text-indent: -0.5em` 处理段首开引号 | 段首的开引号不悬挂会让首行看起来缩进了半格,视觉左边缘不齐 |
|
|
|
+| 连续标点挤压 | `font-feature-settings: "halt";`(行尾挤压)或 `"palt"`(全比例宽度,需配合 letter-spacing) | 全角标点连排(如「)。」)会出现一个半字宽的空洞,halt 收窄它 |
|
|
|
+
|
|
|
+### 4.5 中文 letter-spacing 区间
|
|
|
+
|
|
|
+| 场景 | 区间 | 为什么 |
|
|
|
+|------|------|--------|
|
|
|
+| 正文 | 0 至 0.05em | 微加字距提升透气度;超过 0.05em 词的完形被打散,读速下降 |
|
|
|
+| 标题(24-48px) | 0 | 汉字方块字距天然均匀,不需要西文式 tracking 调整 |
|
|
|
+| display 巨字(>60px) | -0.02em 至 0 | 大字号下字面之间的空隙被放大,微收更紧凑;再负就笔画相撞 |
|
|
|
+| 全大写西文小标签 | 0.08-0.15em | 唯一需要大正字距的场景,且只对西文大写生效 |
|
|
|
+
|
|
|
+**中文永远不要用西文那套「display 收 -0.05em」**:汉字是满格设计,负字距直接笔画打架。
|
|
|
+
|
|
|
+### 4.6 中文 display 大字
|
|
|
+
|
|
|
+中文没有西文那种 Ultra Thin 到 Black 的 display 字体生态,大字的戏剧性要靠推理制造:
|
|
|
+
|
|
|
+- **字重对比是主武器**:思源宋 Heavy 900 压 Light 300,同一字体两个极端字重同屏,比换字体更有张力且零加载成本
|
|
|
+- **笔画密度决定可用字号下限**:笔画细/反差大的字体(宋体细横、Cormorant 式)只在大字号成立;小于 24px 细笔画开始断笔,正文必须回到黑体/中等笔画
|
|
|
+- **反向也成立**:笔画重的字(黑体 Black、老宋)在超大字号下墨量过大,「一」和「灥」墨量差被放大,密度不均的标题考虑换低一档字重
|
|
|
+- **竖排是中文独有的 display 武器**:`writing-mode: vertical-rl` 做书脊式标题、诗词、目录,西文做不到;注意竖排里的西文和数字用 `text-orientation: upright` 或 `text-combine-upright: all`(两位数字合体直立)
|
|
|
+
|
|
|
+## 5. 反模式清单
|
|
|
+
|
|
|
+| ❌ 反模式 | 为什么错 |
|
|
|
+|-----------|----------|
|
|
|
+| 全场 Inter(display+body 一把梭) | Inter 是 UI 小字工具,当 display 匀质无表情;这是「AI 生成页面」的头号指纹 |
|
|
|
+| 中文交给 `sans-serif` 系统默认 | Windows 落到中易宋体/雅黑、macOS 落到苹方,同一页面跨设备完全两张脸,等于没做设计 |
|
|
|
+| faux italic / faux bold | 浏览器合成变形:斜体扭曲汉字,合成加粗把笔画糊成墨团;用 `font-synthesis: none` 断根 |
|
|
|
+| 大标题字距过松 | 西文 display 需要收紧(大字号空隙被放大),AI 常反着来加 +0.05em,标题松垮像临时占位 |
|
|
|
+| 行长失控(无 max-width) | 大屏上一行 60 个汉字,读者回行必迷路;可读性问题里行长失控排第一,比字体选错伤害大 |
|
|
|
+| 字号档位 >6 档 | 层级贬值,读者分不清什么重要;音阶的意义就是强制克制 |
|
|
|
+| 只有 400/700 两档字重 | 层级全靠字号撑,页面平;variable font 时代 300-900 都是免费的表达维度 |
|
|
|
+| 表格/数据不用 tabular-nums | 数字宽度不等,列左右抖动,数据可信感直接打折 |
|
|
|
+| 中文正文用 display 字体(得意黑/老宋整段排) | display 字体的个性在正文里变成阅读阻力,200 字后就累 |
|
|
|
+| 中西混排中文字体放 fallback 链最前 | 拉丁字符全被中文字体自带的难看西文吃掉,配好的西文体永远轮不到出场 |
|
|
|
+
|
|
|
+## 6. CSS 实现要点
|
|
|
+
|
|
|
+```css
|
|
|
+:root {
|
|
|
+ /* 1. fallback 链:西文 → 中文 → 系统中文 → 泛型(顺序即规则,见 4.2) */
|
|
|
+ --font-body: "Geist", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
|
|
|
+ --font-display: "Newsreader", "Noto Serif SC", "Songti SC", serif;
|
|
|
+
|
|
|
+ /* 2. 禁合成:不接受浏览器伪造的斜体/加粗(中文场景必开) */
|
|
|
+ font-synthesis: none;
|
|
|
+
|
|
|
+ /* 3. 中文断行底线 */
|
|
|
+ line-break: strict; /* 避头尾 */
|
|
|
+ overflow-wrap: break-word; /* 长 URL/英文串不撑破容器 */
|
|
|
+}
|
|
|
+
|
|
|
+body {
|
|
|
+ font-family: var(--font-body);
|
|
|
+ font-size: 17px; /* 中文正文基准,见第 1 章 */
|
|
|
+ line-height: 1.8; /* 中文行高基准,见第 2 章 */
|
|
|
+ /* 正文开启标准连字,关闭花哨特性 */
|
|
|
+ font-feature-settings: "liga" 1, "calt" 1;
|
|
|
+}
|
|
|
+
|
|
|
+/* 数据场景:等宽数字 + 斜杠零(0 和 O 不混淆) */
|
|
|
+.data, table { font-variant-numeric: tabular-nums slashed-zero; }
|
|
|
+
|
|
|
+/* 西文小标签:全大写 + 大字距的唯一合法场景 */
|
|
|
+.label { text-transform: uppercase; letter-spacing: 0.1em; font-size: 12px; }
|
|
|
+
|
|
|
+/* 标点挤压:中文 display 大字里全角标点的空洞收窄 */
|
|
|
+.display-cjk { font-feature-settings: "halt" 1; }
|
|
|
+```
|
|
|
+
|
|
|
+**中文字体加载**(单文件 5-15MB,直接引全量会毁掉首屏):
|
|
|
+
|
|
|
+- 首选 Google Fonts 的 Noto SC 系(已按 unicode-range 自动切成上百个分片,浏览器只下用到的字)
|
|
|
+- self-host 个性字体(霞鹜/得意黑等)必须先子集化:`cn-font-split` 或 fonttools 的 `pyftsubset`,正文字体按常用 3500 字切,display 字体按实际出现的字符切(一张海报往往只有 20 个字,子集能压到 50KB 以内)
|
|
|
+- `font-display: swap` 保底,中文字体下载慢,白屏等字体是最差体验
|