排版
排版主要在于克制:合理的比例、舒适的间距、足够的对比度。标签、表格单元格、营销标题和文章段落并不共用一套规则。
审查时,阅读渲染后的页面,而不是浏览代码。只有在实际内容长度下,才会暴露出糟糕的换行、孤行和截断问题。
在项目的样式系统中编写每一个修复,并直接使用下方给出的精确数值,而不是看起来相似的等价物。速查表 将每条声明映射到其 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 你未检查的覆盖范围。没有可报告内容时,声明“未发现可操作的排版问题”并报告验证结果。