Community编程与开发github.com

jakubkrehel/better-typography

专注于字体比例、间距、尺寸、可变字体、OpenType 特性、换行、截断等细节,让你的产品排版更加出色。

better-typography 是什么?

该技能是一个排版优化助手,专为 AI 编码代理(如 Claude Code、Cursor、Codex)设计,帮助开发者审查和修复 Web 项目中的排版问题。它强调在 CSS 中使用正确的字体格式(.woff2)、利用高级 OpenType 和可变字体特性(如 tabular-nums 和光学尺寸),并遵循合理的排版比例与语义化命名规范。技能还涵盖了换行策略(如 text-wrap: balance/pretty)、标点符号的正确使用、移动端输入框最小字号 16px 的解决方案,以及下划线、字距、行高等细节处理。它指导代理在审查时阅读渲染后的页面而非代码,并将问题按严重等级分类,以表格形式输出报告。支持所有主流 CSS 框架,但要求开发者使用项目已有的样式系统。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/jakubkrehel/skills/tree/main/skills/better-typography

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

排版

排版主要在于克制:合理的比例、舒适的间距、足够的对比度。标签、表格单元格、营销标题和文章段落并不共用一套规则。

审查时,阅读渲染后的页面,而不是浏览代码。只有在实际内容长度下,才会暴露出糟糕的换行、孤行和截断问题。

在项目的样式系统中编写每一个修复,并直接使用下方给出的精确数值,而不是看起来相似的等价物。速查表 将每条声明映射到其 Tailwind 等价物。

文字本身属于 better-writing。语义化标题结构属于 better-accessibility。空间上的 RTL 布局和逻辑属性属于 better-layout。对比度测量属于 better-colors。此技能负责控制文本在混合方向内容中如何渲染、换行以及表现。

提供正确的格式

在 Web 上使用 .woff2,以获得 Brotli 压缩和广泛的兼容性。.woff 是非常老旧浏览器的后备方案。.ttf 和 .otf 是桌面格式,没有 Web 压缩功能。文件如何加载是项目自身的问题。

优先使用属性而非原始标签

当 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)保留原始标签。轴和特性标签列表见 variable-fonts-and-opentype.md。

加载预期的字重和样式

浏览器会合成当前字体族中不存在的字重或样式,从而扭曲真实的字形。请加载设计所需的所有字形。

font-synthesis: none 可以关闭合成,但这也意味着会消除强调效果而非进行报告。只有在检查了后备字体堆栈中每个必需的粗体、斜体、小型大写、上标和下标形式都保持独立后,才能设置此属性。

更少的字体、字号和字重

极少使用超过三种字体。字重和字号定义了层级;过度使用它们会迅速损害可读性。配对时追求对比而非相似:衬线标题搭配无衬线正文读起来是刻意的,而两个几乎相同的无衬线字体读起来则是个错误。

在 18px 以下时,保持字重为 400 或更大。300 以下的字重仅在 28px 或更大时用于展示;在文本尺寸下会消失不见。配对指南见 choosing-fonts.md。

使用带语义名称的字号比例

定义一小套字号,并尽可能减少偏离。没有系统支撑的硬编码字号在大规模应用中会分崩离析。

当使用规则明确时,像 text-sm 这样单一的默认名称是可以的。在团队中,按用途命名字号(如 text-body-sm),这样规则在其他人的工作中也能存活。比例构建见 spacing-and-sizing.md。

标题大小按级别递减

将标题级别映射到字号比例的递减阶梯上,这样视觉上从属的标题永远不会强于其父标题。相邻级别在字号比例的小端可以共享一个大小,只要字重或间距能保持它们之间的区分。语义化元素属于 better-accessibility;此技能仅设置视觉呈现。

按角色设置行高

标题更紧凑,大约 1.1。正文 1.5 到 1.6。优先使用无单位值,这样行高会随字号缩放;固定的 24px 则不会。

紧凑的行高适用于短文本。任何换行超过三行的内容至少需要 1.4 的行高,即使在高度受限的行中也是如此。

按字号设置字间距

大标题通常稍微负的字间距更好看。小型大写标签需要一点点正的字间距,否则字母会显得拥挤。阅读尺寸下的正文则两者都不需要。

限制行长

行过长会使眼睛难以找到下一行。将长文文本的行长限制在大约 60–75 个字符之间。任何单位都行,只要存在一个限制并且实际行长落在这个范围内。参见单位选择及其像素等价物。

有意识地换行

四条声明,四项任务:

  • text-wrap: balance 将文本均匀分布到各行。用于标题。
  • text-wrap: pretty 避免一个短单词独占最后一行。用于描述。
  • overflow-wrap: break-word 用于长单词、链接或 ID 可能溢出容器的情况。
  • white-space: nowrap 用于标签和徽章,因为那里的换行看起来很奇怪。

在长文文本中跳过 balance 和 pretty。

对变化的数值使用表格数字

默认情况下,数字的宽度不同,因此计时器、计数器和价格在更新时会改变布局。对任何会变化的数值应用 font-variant-numeric: tabular-nums。

在不丢失内容的前提下截断

对于单行,使用 text-overflow: ellipsis 配合 overflow: hidden 和 white-space: nowrap。对于多行,使用 line-clamp。截断会隐藏内容。当缺失的文本很重要时,确保在工具提示或展开视图中可以访问完整值。

自然书写文本,用 CSS 控制样式

以自然大小写存储文本,并通过 text-transform 控制呈现,这样重新设计时永远不需要重写文案。

在渲染的文本中使用智能标点:

  • 正文中使用弯引号,代码中使用直引号。
  • 范围使用 en 破折号:2010–2020。
  • 使用单个省略号字符,而不是三个句点。
  • 使用   将 16 px 保持在一起,避免在换行时被分开。
  • 使用 ­ 指定长单词可能在哪里断开。

从字体获取下划线

默认的下划线位置由浏览器决定。通过 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。

移动端输入框字号设为 16px

当输入框文本小于 16px 时,iOS Safari 会缩放整个页面。有两种修复方法可以保持字号为 16px,但外观不同,因此请询问设计想要哪一种:

  • 在移动端放大输入框(text-base sm:text-sm)。会改变其在小型屏幕上的外观。
  • 保持 font-size: 16px,并通过 transform: scale() 渲染目标字号,同时补偿宽度和 line-height。在所有视口下外观一致,但需要维护更多代码。

两种方案的具体实现见 details-and-accessibility.md。

字号和对比度下限

长文正文从 16px 开始,这是浏览器默认值。只有当你能够说出一个理由时才偏离它:字体偏小、行长较窄,或者产品是密集的专业工具。

UI 文本可以更小。14px 对于输入框和菜单来说是一个有用的起点,13px 用于说明文字,很少低于 12px。移动端输入框仍然需要 16px。

当文本看起来对比度低时,使用 better-colors 测量渲染后的颜色对,使用 better-accessibility 对需求进行分类。除非被要求,否则不要修改颜色。

在根元素上设置字体平滑

在 macOS 上,文本渲染得比预期更重。在根布局上应用一次 -webkit-font-smoothing: antialiased 和 -moz-osx-font-smoothing: grayscale,永远不要在组件级别使用。Tailwind 的 antialiased 涵盖了这两者。

语言和双向行为

设置 lang,以便浏览器和辅助技术选择正确的发音、引号和断字。在文档级别或内容方向改变处设置 dir。保留数字顺序,并使用 <bdi> 隔离混合方向的值。空间镜像和逻辑 CSS 属性属于 better-layout。

保持有用的文本可选

默认保持文本可选。::selection 可以将品牌特色带入阅读体验,只要被选中的组合保持清晰可辨即可。

user-select: none 适用于拖拽或手势驱动的界面,在这些地方意外选择会干扰操作。永远不要在整个界面上使用,也永远不要因为按钮标签可以被高亮而使用。

完成前检查

错误修复
合成的字形与设计不符加载真实字形;仅禁用已验证的合成模式
子标题在视觉上强于父标题将该部分的层级映射到递减的比例阶梯
因默认字号而选错标题元素先选择语义,然后通过 CSS 设置大小
段落最后一行出现孤行text-wrap: pretty
两行标题不对称text-wrap: balance
界面中对齐文本text-align: start;仅为特定的编辑布局保留两端对齐
下划线切穿字母下行部分text-decoration-skip-ink: auto,from-font 度量
混合方向的值以错误顺序渲染修正 lang/dir;使用 <bdi> 隔离该值
跨应用界面的选择被禁用恢复选择;仅在与拖拽或手势冲突的地方禁用
额外信息提示但无视觉提示通过 text-decoration-style: dotted 使用点状下划线
14px UI 文本使用细/瘦字重18px 以下使用字重 400+;细字重仅用于展示
三行卡片描述上使用 leading-none任何换行到 3 行以上的文本至少使用 1.4 行高

报告

严重等级。 HIGH 使文本不可读,或者截断内容且无法恢复。MEDIUM 破坏了字体系统或标题层级。LOW 是孤立的润色问题。

验证。 无浏览器:检查每个标题级别的计算后的字号和字重,确保是递减的;声明的行高和行长;针对真实字符串长度的截断规则。有浏览器:调整视口大小以捕获实际内容长度下的换行、孤行和截断问题。报告你无法运行的每一个检查,标记为 Not verified。

格式。 按每条违反的原则对发现项进行分组,按严重等级排序,每个根本原因一行,列出它出现的每个位置:

严重等级位置修复前修复后原因

位置 是 path/to/file:line。原因 指出违反的原则和用户影响。

当任何 HIGH 遗留时,以 Block 结束;否则以 Approve 结束,将剩余问题留在表中作为待办工作。永远不要 Approve 你未检查的覆盖范围。没有可报告内容时,声明“未发现可操作的排版问题”并报告验证结果。

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

相关技能