排版规则
排版的要义在于克制:合理的比例、舒适的间距、足够的对比度。标签、表格单元格、营销标题和文章段落并不共享同一套规则。
审查时,请阅读渲染后的页面,而不是扫描代码。坏换行、孤行和截断问题只有在真实内容长度下才会显现。
所有修复请使用项目的样式系统,并采用下面给出的精确值,而不是看起来相似的等价写法。速查表将每个声明映射为其 Tailwind 等效写法。
文字内容本身属于 hr-better-writing。语义化的标题结构属于 hr-better-accessibility。空间上的 RTL 布局和逻辑属性属于 hr-better-layout。对比度测量属于 hr-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。
使用语义化的字号比例
定义一小套字号大小,并尽可能不偏离它。背后没有体系的硬编码字号在规模扩大时会崩溃。请使用 lint 规则或防护测试来强制执行此比例,该测试会在遇到任意非标准字号时失败。
当使用规则清晰时,像 text-sm 这样的独立默认名称是可以的。在团队中,请按用途命名字号(如 text-body-sm),以便规则能在他人的使用中存活。比例构建详见 spacing-and-sizing.md。
标题大小随级别递减
将标题级别映射到字号比例的递减步骤,使得视觉上次级的标题永远不会压制其父级。相邻级别在比例的小端可能共享一个字号,只要字重或间距能保持它们的区分。语义元素是 hr-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。截断会隐藏内容。当缺失的文本很重要时,请通过工具提示或展开视图保留完整值。
按字段选择。对用户需要完整识别项目的名称和标题进行包裹。当项目在末尾不同时(例如共享域名的文件名、路径和电子邮件),在中间进行截断,因为末尾的省略号会使它们看起来相同。切勿截断用户比较的数字、金额或日期。详情参见 wrapping-and-punctuation.md。
自然地书写文案,用 CSS 进行样式化
以自然大小写存储文本,并通过 text-transform 控制呈现方式,这样重新设计时就不必重写文案。
在渲染的文本中使用智能标点:
- 散文中使用弯引号,代码中使用直引号。
- 范围使用短破折号:
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。
当文本看起来对比度低时,使用 hr-better-colors 测量渲染的对,并使用 hr-better-accessibility 对要求进行分类。除非被要求,否则不要修改颜色。
在根元素上开启字体平滑
在 macOS 上,文本渲染得比预期更粗。在根布局上一次性应用 -webkit-font-smoothing: antialiased 和 -moz-osx-font-smoothing: grayscale,切勿逐组件使用。Tailwind 的 antialiased 涵盖了这两者。
语言和双向行为
设置 lang,以便浏览器和辅助技术选择正确的发音、引号和断字。在文档级别或内容方向发生变化的内容边界设置 dir。保留数字顺序,并使用 <bdi> 隔离混合方向的值。空间镜像和逻辑 CSS 属性属于 hr-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 以下使用 weight 400+;细字重仅限显示用途 |
三行卡片描述中使用 leading-none | 任何包裹到 3+ 行的文本至少使用 1.4 |
报告
严重性。 HIGH 使文本不可读或截断内容且无法恢复。MEDIUM 破坏类型系统或标题层次结构。LOW 是孤立的打磨细节。
验证。 无浏览器时:检查每个标题级别的计算字号和字重,确保递减;检查声明的行高和行宽;根据实际字符串长度检查截断规则。有浏览器时:调整视口大小以捕捉真实内容长度下的换行、孤行和截断。将每个无法运行的检查报告为 未验证。
格式。 将发现按违反的原则分组,按严重性排序,每行一个根因,列出其出现的每个位置:
| 严重性 | 位置 | 之前 | 之后 | 原因 |
|---|
位置 是 path/to/file:line。原因 指出原则和用户影响。
当存在任何 HIGH 时报告 阻断,否则报告 批准,并将剩余问题留在表中作为待办事项。切勿批准你未检查的覆盖范围。无内容可报告时,注明“无可行的排版发现”并报告验证情况。