Wensity 排版设计
在界面中,字体承担了大部分工作。做得对,一个朴素的页面也能看起来经过精心设计;做得不对,再多的色彩或动效也无法弥补。本技能为你提供一个一次性设置好的系统,以及适用于所有场景的规则。
以下值为默认值。如果项目已有排版系统,请保留它并改进其使用方式。仅在明确要求时才替换它。
1. 选择字体族
- 通常一个字体族就足够了。 一个好的、具有真实字重范围的无衬线字体,可以覆盖展示、标题、正文和 UI 文字。只有当第一个字体族无法胜任某个角色时,才添加第二个字体族:例如,为营销页面添加一个有特色的展示无衬线字体,或者为代码和数据添加等宽字体。
- 仅无衬线:不要衬线和斜体。 标题、正文、引用和说明文字都统一使用正体的无衬线字体。在 Web 产品上,使用衬线字体的标题或斜体的行会看起来像套用模板,因此两者都不使用,即使是在博客、文档和奢侈品页面上也是如此;通过字重、大小和间距来传达语气。
- 最多使用两个字体族加上一个等宽字体。 第三个文本字体族会显得犹豫不决。
- 根据主题选择,而不是凭习惯。 不要在每个项目上都使用同一个字体。思考该产品在印刷品或硬件上看起来是什么样,然后选择具有那种特质的字体:
| 产品感觉像 | 选择 | 免费示例 |
|---|---|---|
| 精确工具(开发者工具、数据、基础设施) | 紧凑的 grotesk 字体,数据中用等宽字体 | Geist, Switzer, Onest; Geist Mono, JetBrains Mono |
| 沉稳的金融或健康(金融、保险、诊所) | 稳定的 neo-grotesk 或 humanist 无衬线字体 | Inter, Public Sans, Source Sans 3 |
| 友好的消费者(社交、美食、旅游、教育) | 圆润的几何或 humanist 无衬线字体 | Plus Jakarta Sans, Figtree, Nunito Sans, DM Sans |
| 自信的品牌或初创公司营销页面 | 在展示尺寸下有个性的无衬线字体 | General Sans, Manrope, Bricolage Grotesque, Space Grotesk |
| 阅读和出版(文档、博客、杂志) | 具有真正正文切割的平静无衬线字体,同一字体族的紧凑标题 | Inter, Satoshi, Source Sans 3 |
| 时尚、编辑或奢侈品 | 精致的展示无衬线字体,设置得大而紧凑,仅用于标题 | Satoshi, General Sans, Clash Grotesk |
- 检查字体能否胜任工作: 你需要的字重(通常是 400, 500, 600)、表格数字、良好的标点符号、你发布的语言版本,以及如果你使用多种字重,则需要一个可变版本。
2. 定义角色,而非尺寸
根据其工作命名文本。组件使用角色名称;只有角色定义包含像素值。七个角色几乎覆盖所有界面:
| 角色 | 用于 | 营销页面 | 应用 UI |
|---|---|---|---|
display | 主打标题,每页一个 | 48 到 80px,字重 600,行高 0.95 到 1.05,字间距 -0.03em 到 -0.04em | 很少使用 |
title | 页面和章节标题 | 32 到 44px,字重 600,行高 1.1,字间距 -0.02em | 20 到 24px,字重 600,行高 1.25,字间距 -0.01em |
heading | 卡片、面板和子节标题 | 20 到 24px,字重 600,行高 1.25,字间距 -0.01em | 15 到 16px,字重 600,行高 1.4 |
body | 段落 | 16 到 18px,字重 400,行高 1.55 到 1.65 | 14 到 15px,字重 400,行高 1.5 |
label | 按钮、输入框、导航、表格标题 | 14 到 15px,字重 500,行高 1.3 | 13 到 14px,字重 500,行高 1.3 |
caption | 辅助文本、元数据、时间戳 | 13 到 14px,字重 400,行高 1.45 | 12 到 13px,字重 400,行高 1.4 |
code | 行内代码、代码块、ID | 周围文本的 0.9em,等宽 | 相同 |
关于字阶的规则:
- 相邻角色的区别必须明显。 相邻角色的大小至少相差约 20%,或者在大小阶梯的基础上再增加一个字重阶梯(14px 500 的 label 放在 13px 400 的 caption 上是可以的;但 15px 400 紧挨着 16px 400 做不同的工作就不行)。
- 比例有帮助,但表格为准。 营销页面适合步骤之间比例为 1.25 到 1.333;密集的应用 UI 适合 1.125 到 1.2。取整到整像素。
- 最多三种字重: 常规 (400),用于标签的中等字重 (500),用于标题和展示的半粗 (600)。层级也来自大小、颜色和空间,因此不需要五种字重。如果 600 对于大展示行来说看起来太粗,那么对展示使用 500,而不是增加第四种字重。
- 仅在营销页面上对 display 和 title 使用流体尺寸:
font-size: clamp(2.5rem, 1.5rem + 4vw, 5rem)。保持正文和 UI 文本固定,使密集布局保持可预测。 - 正文文本下限: 营销和阅读页面为 16px,密集应用 UI 中为 14px。移动设备上的输入文本为 16px,否则 iOS Safari 会在字段获得焦点时缩放页面。
在 Tailwind CSS v4 中,一次性定义角色(将字体族名称替换为你选择的):
@theme {
--text-display: clamp(2.75rem, 1.6rem + 4.2vw, 5rem);
--text-display--line-height: 1;
--text-display--letter-spacing: -0.035em;
--text-display--font-weight: 600;
--text-title: 2.25rem;
--text-title--line-height: 1.1;
--text-title--letter-spacing: -0.02em;
--text-title--font-weight: 600;
--text-heading: 1.25rem;
--text-heading--line-height: 1.3;
--text-heading--letter-spacing: -0.01em;
--text-heading--font-weight: 600;
--text-body: 1rem;
--text-body--line-height: 1.6;
--text-label: 0.875rem;
--text-label--line-height: 1.3;
--text-label--font-weight: 500;
--text-caption: 0.8125rem;
--text-caption--line-height: 1.45;
}
然后在标记中使用 text-display、text-title、text-body,而不是 text-[44px] 或一长串的 text-4xl leading-tight tracking-tight。在 Tailwind v3 中,将相同的值作为 [size, { lineHeight, letterSpacing, fontWeight }] 元组放入 theme.extend.fontSize 下。
3. 行高和字间距
- 行高随尺寸增大而减小。 Display:0.95 到 1.05,标题:1.1 到 1.2,正文:1.5 到 1.65,标签:1.2 到 1.35。一个 64px 的标题,行高为 1.5,会散架成单独的行。
- 大文本使用紧凑字间距,正文不使用。 Display:-0.03em 到 -0.04em,标题:-0.02em,heading:-0.01em,正文和标签:0。不要比 -0.05em 更紧;字母会开始接触。根据你选择的字体用肉眼微调。
- 小写正文和界面文本上不要使用正字间距。 正字间距仅对全大写文本有帮助,而全大写文本应该很少见(见第 6 节)。
- 宽行需要更大的行距。 如果正文文本接近每行 75 个字符,则使用行高 1.6 或更高;在 50 个字符时,1.5 就足够了。
- 深色背景上的浅色文本看起来更重、更紧凑。 在深色主题上,正文行高增加约 0.05。
4. 行长和断行
- 正文文本:每行 60 到 75 个字符。 在段落上设置
max-width: 65ch,而不是在整个页面上。说明文字和辅助文本可以更窄。 - 展示标题:每行约 12 到 20 个字符。 一个横跨 1440px 屏幕的单行标题没有形状。使用
ch单位的max-width或容器宽度来约束它。 - 平衡标题,优雅地换行段落:
h1, h2, h3, .text-display, .text-title { text-wrap: balance; }
p, li, figcaption { text-wrap: pretty; }
两者都是渐进的:旧浏览器会忽略它们。balance 使标题行均匀分布;pretty 防止段落最后一行单独出现一个单词。
- 仅在短语之间手动断行,并在文本呈现的每个宽度下检查它们。放在手机上可能位于行中的
<br>比默认换行更糟糕。优先使用max-width而不是<br>。 - 用户内容中的长单词和 URL 需要在其容器上设置
overflow-wrap: anywhere,否则它们会在移动端将布局推至一侧。 - 截断是最后的手段。 在紧凑的 UI 中截断单行标签(Tailwind 中的
truncate)。如果隐藏的部分很重要,请确保全文本可通过键盘和触摸访问(可聚焦元素上的 tooltip、可展开的行、详细视图);单独的title属性是不够的。永远不要截断正文文本或用户必须阅读才能操作的内容。 - 多行限制(
line-clamp-2):在被限制的文本上保持行高为 1.3 或更高,这样下伸部分(g, y, p)不会被切断。不要在限制内部添加底部内边距;它会显示下一行的顶部。
5. 文本颜色和对比度
- 三种文本颜色就足够了: 主要(标题和正文)、次要(支持文本、说明文字、占位符)和禁用。将它们定义为令牌。避免通过动态降低不透明度来创建第四种颜色。
- 对比度下限(WCAG 2.2 AA): 正文和小文本为 4.5:1,24px 及以上的文本(或 18.66px 粗体)为 3:1。次要文本和占位符文本也需要 4.5:1。只有禁用控件中的文本可以例外。
- 在深色背景上使用灰白色,而非纯白色,用于长篇文本(大约 90% 到 94% 的亮度)。近黑色背景上的纯白色会刺眼。
- 在彩色或着色表面上, 将次要文本的颜色调向表面色调,而不是使用中性灰,后者在颜色上看起来脏。
6. 应避免的内容
- 标题上方的眉题和引子行: 标题上方的小型大写字母、增加字间距的标签(“功能”、“为什么选择我们”、“工作原理”)。不要使用它们。它们是模板 UI 最明显的标志。如果标题需要上下文,请写一个更好的标题。
- 一般情况下的全大写标签, 包括侧边栏、设置面板、卡片、页脚和演示控件中的小型章节标题。句子大小写读起来更快;给小型标题一个字重(500 或 600)和次要文本颜色。将大写字母保留给真正的缩写(API, URL)。
- 渐变文本和标题中的一个彩色词。 强调来自大小、字重和位置,而不是颜色。
- 任何地方的斜体。 使用字重进行强调,并将引用设置为正体,旁边加一条规则或更大的尺寸。
- 衬线字体。 展示衬线和文本衬线在 Web 产品上看起来都像服装。选择有个性的无衬线字体。
- 作为装饰的等宽字体。 Mono 用于代码、数据、ID、键盘按键和列中的数字。营销页面上的等宽标签是一种服装。
- 超过两行的居中段落。 仅居中短标题和单行 CTA。
- 网页上的两端对齐文本。 没有连字符会导致空白河流。
- 除链接外的任何内容使用下划线。
7. 数字、代码和数据
- 在需要对齐或更新的任何内容中使用表格数字: 表格、价格、计时器、计数器、统计数据。
font-variant-numeric: tabular-nums;(Tailwindtabular-nums)。没有它,计数的数字会因数字宽度变化而横向抖动。 - ID 和代码中使用带斜线零,当 0 和 O 可能混淆时:
font-variant-numeric: tabular-nums slashed-zero;。 - 在表格单元格末尾对齐数字(
text-align: end),以便小数点对齐。文本列在开头对齐。 - 代码: 约为周围文本 0.9em 的等宽字体,使其 x 高度匹配。行内代码获得微妙的背景和 0.2em 水平内边距,无边框。代码块获得约 1.6 的行高和水平滚动,永远不要换行破坏缩进。
- 键盘按键(
<kbd>)使用说明文字大小的等宽字体。
8. 链接
在正文文本中给链接加下划线;仅靠颜色对色盲读者无效。将其范围限定在散文内,以便导航列表和按钮不加下划线(.prose 是任何包裹你文章或长格式内容的容器):
:where(p, td, dd, figcaption, blockquote) a,
:where(.prose, article) li a {
text-decoration-line: underline;
text-decoration-thickness: 1px;
text-underline-offset: 0.2em;
}
导航、按钮和卡片链接不需要下划线;它们的位置已经表明它们是交互式的。
9. 在不引起布局偏移的情况下加载字体
- Next.js: 使用
next/font(next/font/google或next/font/local)。它会自托管、预加载并生成具有匹配度量的后备字体,这样页面不会在字体加载时跳动。将其公开为 CSS 变量,并使用@theme inline将主题字体映射到它(这样变量在其使用的位置被读取,而不是在:root处一次性解析):
// app/layout.tsx
import { Onest } from "next/font/google";
const sans = Onest({ subsets: ["latin"], variable: "--font-brand", display: "swap" });
// <html lang="en" className={sans.variable}>
@theme inline {
--font-sans: var(--font-brand), ui-sans-serif, system-ui, sans-serif;
}
- 光学尺寸: 具有
opsz轴的字体(Inter, Roboto Flex, Fraunces)只有在加载它时才能获得:Inter({ subsets: ["latin"], axes: ["opsz"] })。保持font-optical-sizing: auto,这样小文本获得更结实的切割,大文本获得更精细的切割。 - 其他情况: 自托管 WOFF2,
font-display: swap,仅预加载首屏上方使用的一两个文件,并在本地后备字体上设置size-adjust、ascent-override和descent-override,以便交换时不会引起布局偏移。 - 只加载你使用的部分。 优先选择一个可变字体文件,而不是六个静态字重。根据需要发布的脚本进行子集化。
10. 渲染细节
- 在深色主题上使用
-webkit-font-smoothing: antialiased使浅色文本在 macOS 上看起来不那么臃肿。浅色主题保持默认设置。 - 将
::selection设置为品牌色调并保持可读性。浏览器的默认蓝色是页面尚未完成的标志。 - 在文案中使用真实的标点符号:弯引号(“ ” ‘ ’)、省略号字符(…)和尺寸中的乘号(×)。
- 尊重用户设置:以
rem为单位设置文本大小,永远不要阻止缩放,并检查文本在 200% 文字大小以及更大的字母和行间距下是否仍然合适。
11. 完成后检查
- 每个文本样式都来自命名角色;没有零散的像素尺寸。
- 相邻角色在大小或大小加字重上有明显区别。
- 最多两个字体族加 mono,最多三种字重,全部已加载。
- 正文文本 16px(密集 UI 14px),移动设备上输入框 16px。
- 段落限制在大约 65ch;展示行大约 12 到 20 个字符。
- 标题已平衡,段落已优雅换行。
- 没有眉题,没有渐变文本,没有彩色字。
- 所有数字(价格、表格、统计数据、计时器)使用表格数字。
- 正文文本中的链接有下划线;导航链接没有。
- 三种文本颜色(主要、次要、禁用)定义了令牌;所有文本通过 WCAG AA 对比度测试。
- 字体已加载,没有布局偏移。
- 没有衬线、斜体、全大写标签或两端对齐文本。
- 文本换行使用
balance和pretty。 - 256px 文本大小和双倍行间距下布局仍然完整,没有文本溢出或重叠。