
better-typography
热门Web 排版,涵盖字体选择、间距、换行和可访问性。在挑选或搭配字体、配置可变字体或 OpenType 特性、设置字号层级、检查标题层级、为组件中的文本设置样式、截断文本、设置下划线、选中状态、占位符或光标样式,或审查前端代码中的排版时使用。触发条件:排版、字体、字体格式、woff2、可变字体、font-weight、opentype、font-feature-settings、letter-spacing、line-height、字号层级、标题层级、标题级别、表格数字、text-wrap、截断、line clamp、下划线、text-decoration、文本选中、iOS 输入缩放、字体平滑、文本对比度、行长、行宽、text-box、智能标点、首字下沉。
Web 排版,涵盖字体选择、间距、换行和可访问性。在挑选或搭配字体、配置可变字体或 OpenType 特性、设置字号层级、检查标题层级、为组件中的文本设置样式、截断文本、设置下划线、选中状态、占位符或光标样式,或审查前端代码中的排版时使用。触发条件:排版、字体、字体格式、woff2、可变字体、font-weight、opentype、font-feature-settings、letter-spacing、line-height、字号层级、标题层级、标题级别、表格数字、text-wrap、截断、line clamp、下划线、text-decoration、文本选中、iOS 输入缩放、字体平滑、文本对比度、行长、行宽、text-box、智能标点、首字下沉。
优秀的排版
好的排版主要是克制。合理的字号层级、舒适的间距和足够的对比度胜过任何花哨的效果。标签、表格单元格、营销标题和文章段落不应共用一套规则。在构建或审查任何包含文本的内容时,应用这些原则。
审查时,阅读页面而非扫描代码:眯眼检查层级是否合理,通读一个完整段落以确认舒适度,并调整视口大小以捕捉实际内容长度下的不良换行、孤行和截断。
词语本身(按钮标签、错误消息、空状态)由 better-writing 技能覆盖;语义标题结构由 better-accessibility 覆盖;空间 RTL 布局和逻辑 CSS 属性由 better-layout 覆盖;渲染对对比度测量和颜色修复由 better-colors 覆盖。本技能负责文本的渲染、换行以及在混合方向内容中的行为。
匹配项目的样式系统。 在建议或编写任何修复之前,检查代码库的样式方式,并用该体系表达所有更改:Tailwind 项目中使用 Tailwind 工具类,CSS 中使用普通声明,CSS Modules、styled-components 或 StyleX。速查表 将每个声明映射到其 Tailwind 等效项。切勿为了应用排版修复而引入第二种样式方法。
快速参考
| 类别 | 使用时机 | 参考 |
|---|---|---|
| 选择字体 | 字体类别、搭配、格式、字体解剖 | choosing-fonts.md |
| 可变字体与 OpenType | 轴、字重、表格数字、样式集 | variable-fonts-and-opentype.md |
| 间距与大小 | 字号层级、标题层级、行高、字间距、文本修剪 | spacing-and-sizing.md |
| 换行与标点 | 行长、换行、截断、智能标点、RTL | wrapping-and-punctuation.md |
| 细节与可访问性 | 下划线、选中、表单、装饰性文本、对比度 | details-and-accessibility.md |
| CSS 速查表 | 快速查找所有涉及的属性,附 Tailwind 等效项 | css-cheat-sheet.md |
核心原则
1. 提供正确的格式
在 Web 上使用 .woff2(Brotli 压缩,广泛支持)。.woff 仅作为非常老旧浏览器的后备;.ttf 和 .otf 是原始桌面格式,没有 Web 压缩。文件如何加载是项目自身的问题,本技能不规定。
2. 优先使用属性而非原始标签
当 CSS 属性存在时,使用它。使用 font-weight: 650 而非 font-variation-settings: "wght" 650,font-optical-sizing: auto 而非 "opsz",font-variant-numeric: tabular-nums 而非 font-feature-settings: "tnum" 1。属性在非可变后备渲染时仍能工作。将原始标签属性保留给自定义轴("GRAD" 80)和没有对应属性的小众特性("ss01" 1)。
3. 加载预期的字重和样式
浏览器可能会合成当前字体族未提供的请求字重或样式。优先加载设计实际使用的字面。仅在验证了所有需要的粗体、斜体、小型大写、上标和下标形式在整个后备堆栈中视觉上可区分后,才设置 font-synthesis: none;禁用合成不是诊断手段,且不得消除强调。
4. 更少的字体、字号和字重
很少使用超过三种字体。字重和字号定义层级,但过度使用会迅速损害可读性。搭配时追求对比而非相似:衬线标题搭配无衬线正文显得有设计感,两个几乎相同的无衬线字体则显得像错误。在 18px 以下,保持字重 400+;低于 300 的字重仅用于展示(28px+),在文本尺寸下会消失。
5. 使用带有语义名称的字号层级
定义一小套字号,并尽可能少地偏离它。没有系统的硬编码字号在规模上会崩溃。对于个人项目,默认名称如 text-sm 可以工作,只要使用规则清晰。在团队中,按用途命名字号(text-body-sm),而非按大小,以便规则保持一致。
6. 标题大小随层级递减
在连贯的页面层级中,将标题级别映射到字号层级的递减步骤:视觉上从属的标题不应意外地压倒其父级。相邻级别在层级的小端可以共享一个大小,只要字重或间距保持它们可区分。根据 better-accessibility 选择语义标题元素;本技能仅控制其视觉处理。
7. 按角色设置行高
标题更紧凑,大约 1.1。正文 1.5 到 1.6。优先使用无单位值,以便行高随字号缩放;固定值如 24px 则不会。紧凑行高适用于短文本:任何换行到三行或以上的文本至少需要 1.4,即使在高度受限的行中也是如此。
8. 按大小设置字间距
大标题通常看起来略微负字间距更好。小写标签需要一点正字间距,以免字母显得拥挤。阅读尺寸的正文两者都不需要。
9. 限制行长
长行使眼睛难以找到下一行。将长文本限制在每行 60–75 个字符左右。任何单位都可以:65ch 直接测量字符,像素或 rem 限制也同样好:在 16px 正文大小下,范围大致在 560px 和 680px 之间,具体取决于字体,因此 Tailwind 的 max-w-xl 或 max-w-2xl 适合。重要的是存在一个限制,并且结果行长度在范围内。
10. 有意识地换行
text-wrap: balance 使文本均匀分布在各行:用于标题。text-wrap: pretty 避免在最后一行留下单个短词:用于描述。在长文本中跳过两者:浏览器在几行后忽略 balance,而均匀分布整个段落会浪费空间并使阅读更困难。overflow-wrap: break-word 用于长单词、链接或 ID 可能溢出容器的情况。white-space: nowrap 用于标签和徽章,其中换行看起来不完整。
11. 对变化的值使用表格数字
默认情况下数字宽度不同,因此计时器、计数器和价格在更新时会移动布局。对任何变化的值应用 font-variant-numeric: tabular-nums。
12. 截断而不丢失内容
单行:text-overflow: ellipsis 配合 overflow: hidden 和 white-space: nowrap。多行:line-clamp。截断会隐藏内容,因此如果缺失的文本重要,请确保完整值可通过工具提示或展开视图访问。
13. 自然书写文案,用 CSS 设置样式
以自然大小写存储文本,并通过 text-transform 控制呈现,这样重新设计时无需重写文案。使用智能标点:散文中使用弯引号(代码中使用直引号),范围如 2010–2020 使用短破折号,插入想法使用长破折号,单个省略号字符,使用 保持像 16 px 这样的值在一起,使用 ­ 控制长单词可能断开的位置。
14. 从字体获取下划线
默认下划线位于浏览器决定的任何位置。使用 text-underline-position: from-font 和 text-decoration-thickness: from-font 从字体自身的度量中提取位置和粗细,或手动调整 text-decoration-thickness、text-underline-offset 和 text-decoration-skip-ink。text-decoration-style 绘制虚线、点线或波浪线;点线下划线是常见提示,表示单词携带额外信息,如缩写或定义术语。除非动画仅涉及颜色变化,否则将下划线构建为单独元素,而不是使用 text-decoration:颜色是真实下划线中唯一可靠动画的部分。
15. 移动端输入框使用 16px
iOS Safari 在输入框文本小于 16px 时会缩放整个页面。在移动视口上保持输入框文本为 16px(text-base sm:text-sm)。避免使用 maximum-scale=1 视口 meta:Safari 会忽略它进行捏合缩放,但其他所有浏览器都会遵守并阻止缩放,这违反了 WCAG。
16. 字号和对比度下限
长文本正文从浏览器默认的 16px 开始,然后根据实际字体、行长、平台和产品密度进行判断。UI 文本可以更小:14px 是输入框和菜单的有用起点(输入框在移动端仍需要 16px,见原则 15),13px 用于说明文字,很少低于 12px。当文本看起来对比度低时,使用 better-colors 测量渲染对,并使用 better-accessibility 分类要求;除非要求,否则不要更改颜色。
17. 在根元素上设置字体平滑
在 macOS 上,文本渲染比预期更粗。在根布局上应用一次 -webkit-font-smoothing: antialiased 和 -moz-osx-font-smoothing: grayscale(两者都由 Tailwind 的 antialiased 覆盖),以便覆盖所有文本。
18. 语言和双向文本行为
设置 lang 以便浏览器和辅助技术选择正确的发音、引号和连字符。在方向变化的地方设置 dir 在文档或内容边界,保持数字顺序,并在需要时使用 <bdi> 隔离混合方向值。空间镜像和逻辑 CSS 属性属于 better-layout。
19. 保持有用的文本可选中
当选中的组合保持可读时,::selection 可以将品牌带入阅读体验。默认保持文本可选中。仅在特定的可拖动或手势驱动的表面上使用 user-select: none,其中意外选择明显干扰交互;切勿在整个界面中禁用选择,或仅仅因为按钮标签可以被高亮。
常见错误
| 错误 | 修复 |
|---|---|
在 Web 上提供 .ttf/.otf |
转换为 .woff2 |
使用 font-variation-settings: "wght" 设置字重 |
使用 font-weight(与非可变后备兼容) |
使用 font-feature-settings: "tnum" 1 |
使用 font-variant-numeric: tabular-nums |
| 合成字面与预期设计不同 | 加载所需字面;仅禁用已验证的合成模式,不消除强调 |
| 硬编码的一次性字号 | 使用字号层级 |
| 子标题视觉上压倒父标题 | 将该部分的层级映射到递减的层级步骤 |
| 根据默认大小选择标题元素 | 使用 better-accessibility 选择语义,然后在 CSS 中设置视觉大小 |
在可缩放文本上使用 line-height: 24px |
使用无单位值(1.5) |
| 全宽段落 | 限制每行约 60–75 个字符 |
| 段落最后一行出现孤行 | 使用 text-wrap: pretty |
| 两行标题不平衡 | 使用 text-wrap: balance |
| 数字导致布局偏移 | 使用 tabular-nums |
| 截断文本且无法阅读 | 为完整值提供工具提示或展开视图 |
在文案中键入 UPPERCASE |
使用自然大小写 + text-transform |
| 界面中对齐文本 | 使用 text-align: start;仅对特定编辑布局保留两端对齐 |
| 下划线穿过下伸部分 | 使用 text-decoration-skip-ink: auto、from-font 度量 |
iOS 上低于 16px 的输入框缩放 |
使用 text-base sm:text-sm |
| 根布局省略字体平滑 | 在根元素应用一次 antialiased |
| 混合方向值以错误顺序渲染 | 设置正确的 lang/dir;需要时用 <bdi> 隔离值 |
| 整个应用界面禁用选中 | 恢复选中;仅在与拖动或手势冲突的特定交互上抑制 |
| 额外信息提示没有视觉提示 | 通过 text-decoration-style: dotted 使用点线下划线 |
在 14px UI 文本上使用细/轻字重 |
在 18px 以下使用字重 400+;细字重仅用于展示 |
在三行卡片描述上使用 leading-none |
任何换行到 3 行以上的文本至少使用 1.4 |
审查输出格式
仅当用户要求独立的排版审查时使用此格式。当 better-interface 协调审查时,向该技能提供领域证据和发现,并让其输出格式、严重性等级、合并规则、上限和结论优先。
独立审查分为两部分呈现。
发现
按原则分组所有确认的发现。使用包含严重性、位置、之前、之后和原因列的 Markdown 表格。切勿使用单独的“之前:”/“之后:”行。
- 严重性:
HIGH使文本不可读、不可用或结构上误导;MEDIUM损害层级、换行或扫描;LOW是孤立的排版优化。 - 位置:引用
path/to/file:line。如果工件没有源文件,则引用确切的屏幕和组件。 - 之前 / 之后:显示当前排版和可操作的替换。
- 原因:指出违反的原则及其对可读性或层级的影响。
将重复的系统性问题合并为一行,并列出所有受影响的位置。省略没有发现的原则。
示例
表格数字
| 严重性 | 位置 | 之前 | 之后 | 原因 |
|---|---|---|---|---|
| MEDIUM | src/Price.tsx:17 |
实时价格上的 <span>{price}</span> |
<span className="tabular-nums">{price}</span> |
比例数字导致变化的值移动 |
| LOW | src/numbers.css:8 |
font-feature-settings: "tnum" 1 |
font-variant-numeric: tabular-nums |
高级属性保留后备行为 |
行高和行长
| 严重性 | 位置 | 之前 | 之后 | 原因 |
|---|---|---|---|---|
| MEDIUM | src/Article.tsx:33 |
正文段落上的 leading-none |
leading-normal(1.5–1.6) |
换行的正文需要足够的垂直间距 |
| MEDIUM | src/article.css:12 |
全宽文章列 | 在 16px 下接近 65 个字符的 max-width |
长行使行难以跟踪 |
验证和结论
在发现之后:
- 验证:列出执行的确切检查及其观察结果,包括换行、层级、文本缩放、字体加载和动态值稳定性(如适用)。如果未运行检查,说明仍需验证的内容。
- 结论:如果存在任何
HIGH发现,则为Block;如果仅存在MEDIUM或LOW发现,则为Needs changes;仅当没有可操作的发现时,才为Approve。
当没有发现时,省略表格,说明“无可操作的排版发现”,报告验证,并以 Approve 结束。





