布局的响应式早已成为共识,但真正决定一个页面"好不好读"的,往往是文字本身。同样的栅格,在手机上可能字太小、行太长、段落挤成一团;在 4K 显示器上又可能字太细、行长失控、阅读时频繁"串行"。响应式排版(Responsive Typography)要解决的,正是"文字在不同屏幕上都能被舒适阅读"这件事。本文将从单位体系、流体排版公式、模块化比例、行长控制、排版令牌、可变字体、现代 CSS 文本特性到无障碍适配,系统搭建一套可落地的响应式字体与排版系统。35 分钟深度长文,建议收藏后配合代码逐段实践。
为什么响应式排版是"最后一公里"
很多人做响应式时,把 90% 的精力花在栅格、间距、组件折叠上,最后才想起"字号要不要改一下"。结果就是:布局完美,但阅读体验糟糕。排版是用户与内容之间唯一的媒介——用户不会注意到你的栅格是 12 列还是 24 列,但一定会注意到"这段字看着累"。
排版问题通常不会以"报错"的形式出现,而是以"隐性成本"的形式存在:字号太小导致用户放大页面、行长过长导致回扫困难、行高过紧导致行间跳读、字距不当导致中文与西文混排时节奏断裂。这些问题在单一屏幕上不明显,一旦屏幕尺寸跨越 3~4 个量级(手机 320px → 显示器 2560px),就会被急剧放大。
body {
font-size: 16px; /* 从头到尾不变 */
}
h1 {
font-size: 32px; /* 4K 屏上像注释 */
}
p {
max-width: 100%; /* 超宽屏上单行 200+ 字 */
}
/* 真正的响应式排版思路 */
body {
font-size: clamp(16px, 0.9rem + 0.35vw, 20px);
}
h1 {
font-size: clamp(1.75rem, 1rem + 3.2vw, 3.5rem);
}
p {
max-width: 68ch; /* 最佳阅读行长 */
margin-inline: auto;
}
ch 约束,跨屏保持一致阅读节奏响应式排版的目标可以概括为一句话:让文字在任何屏幕上,都保持接近一致的"阅读密度"。所谓阅读密度,包含每行字符数、行高与字号的比值、段落间距与字号的比例关系。这三者只要稳定,用户的阅读体验就稳定。
排版单位体系:px / em / rem / % / vw / ch
要谈响应式排版,必须先厘清单位。不同单位有不同的"参照物",选错参照物,响应式就无从谈起。
body { font-size: 16px; }
/* 2. rem:相对根元素 html 的字号 */
html { font-size: 100%; } /* = 16px */
h2 { font-size: 1.5rem; } /* = 24px */
/* 3. em:相对当前元素(或父元素)的字号 */
.card { font-size: 1.25rem; } /* 20px */
.card p { font-size: 0.9em; } /* 18px,随卡片变化 */
.card p { margin-bottom: 1em; } /* 与字号联动 */
/* 4. 视口单位:vw / vh / vmin / vmax */
h1 { font-size: 4vw; } /* 随视口宽度线性变化 */
.hero { min-height: 100svh; } /* 小视口高度更稳 */
/* 5. ch:当前字体下字符 "0" 的宽度 */
p { max-width: 66ch; } /* 约 66 个字符,最佳行长 */
/* 6. 百分比:相对父元素字号 */
.quote { font-size: 120%; }
字号用 rem,间距用 em,行长用 ch
这里有几个容易被忽略的细节。第一,rem 的参照物是 html 的字号,而用户可以自己在浏览器里调整默认字号——用 rem 意味着你尊重了用户的偏好,用 px 则等于无视它。第二,em 会嵌套累乘,如果你的组件里出现了 font-size: 0.9em 再叠加 padding: 1.2em,最终尺寸会变得难以预测,建议只在"希望与字号联动"的间距、内边距上使用 em。
第三,vw 单独用于字号是把双刃剑:它在小屏上可能小到无法阅读,在大屏上又可能大到荒谬。所以 vw 几乎永远不应该单独出现,而应该出现在 clamp() 的中间参数里。第四,ch 是控制行长的最佳单位,因为它直接对应"一行能放多少个字符",而这个数字与字号无关——无论字号怎么变,66ch 始终是 66 个字符,这正是我们想要的稳定性。
流体排版:clamp() 与线性插值公式
过去我们靠媒体查询在断点上"跳变"字号,问题在于断点之间是静止的,而屏幕是连续的。流体排版(Fluid Typography)让字号在两个边界之间连续、平滑地变化,彻底消除"跳变感"。
现代方案的核心是 clamp(min, preferred, max):它接收三个值,返回"被限制在最小值和最大值之间的首选值"。首选值通常由 rem 加 vw 组合而成,前者保证基础可读性,后者提供随视口增长的增量。
h1 { font-size: clamp(1.75rem, 1rem + 3.2vw, 3.5rem); }
h2 { font-size: clamp(1.4rem, 0.9rem + 2.1vw, 2.4rem); }
h3 { font-size: clamp(1.2rem, 0.9rem + 1.2vw, 1.75rem); }
p { font-size: clamp(1rem, 0.95rem + 0.25vw, 1.15rem); }
/* 精确控制:在 320px 时为 17px,在 1440px 时为 40px */
/* 斜率 = (40 - 17) / (1440 - 320) = 0.0205 */
/* 截距 = 17 - 0.0205 × 320 = 10.43 */
h1 {
font-size: clamp(17px, 10.43px + 2.05vw, 40px);
}
/* 用 calc() 手写完整线性插值(不依赖 clamp) */
h1 {
font-size: calc(17px + 23 * (100vw - 320px) / 1120);
}
/* 用 min() / max() 组合实现同等约束 */
h1 {
font-size: max(17px, min(40px, calc(17px + 23 * (100vw - 320px) / 1120)));
}
/* 更安全的写法:把 vw 部分交给自定义属性,便于统一调节 */
:root {
--fluid-base: 1rem;
--fluid-scale: 0.85vw;
}
h1 {
font-size: clamp(1.75rem, var(--fluid-base) + 3.2 * var(--fluid-scale), 3.5rem);
}
关于 clamp() 有几个实践要点值得强调。第一,最小值不要低于 16px,这是移动端可读性的经验底线;正文最小值通常取 1rem 或 1.0625rem。第二,中间参数的斜率不要过陡,一般控制在 2vw ~ 4vw 之间;斜率越大,字号随窗口变化的幅度越夸张,用户拖动窗口时会感到"文字在缩放",反而分散注意力。
第三,不要忘记 rem 项。如果你写成 clamp(16px, 3vw, 40px),那么当用户把浏览器默认字号调大时,你的标题并不会跟着变大——因为它完全由视口决定。写成 clamp(1rem, 0.9rem + 2vw, 2.5rem) 则同时尊重了用户偏好和视口尺寸,这是更健壮的写法。第四,如果项目需要支持老版本浏览器,可以先用媒体查询给出降级方案,再用 @supports 覆盖。
h1 { font-size: 28px; } /* 兜底 */
@supports (font-size: clamp(1rem, 1vw, 2rem)) {
h1 {
font-size: clamp(1.75rem, 1rem + 3.2vw, 3.5rem);
}
}
模块化比例:让字号之间产生"音乐感"
如果标题、副标题、正文、注释的字号是随手定的,页面会显得杂乱无章。模块化比例(Modular Scale)用固定的比率从一个基准字号推导出整套字号体系,就像音乐中的音阶一样,让不同层级之间保持和谐的倍数关系。
/* 1.125 (Major Second) —— 层级柔和,适合信息密集界面 */
/* 1.200 (Minor Third) —— 通用,最常用于 Web */
/* 1.250 (Major Third) —— 层级分明,适合内容型网站 */
/* 1.333 (Perfect Fourth) —— 强对比,适合营销页面 */
/* 1.618 (Golden Ratio) —— 极致对比,慎用于正文体系 */
/* 以 16px 为基准、比例 1.25 的六级音阶 */
:root {
--step--1: 0.8rem; /* 12.8px 注释 */
--step-0: 1rem; /* 16px 正文 */
--step-1: 1.25rem; /* 20px 小标题 */
--step-2: 1.563rem; /* 25px h3 */
--step-3: 1.953rem; /* 31px h2 */
--step-4: 2.441rem; /* 39px h1 */
--step-5: 3.052rem; /* 49px Hero */
}
/* 移动端换用更小的比例(1.125),避免标题过大 */
@media (max-width: 768px) {
:root {
--step-2: 1.424rem;
--step-3: 1.602rem;
--step-4: 1.802rem;
}
}
/* 进阶:用 pow() 风格的 CSS 变量 + calc 自动生成 */
/* 注意:CSS 原生没有 pow(),可用预处理器或手写 */
:root {
--ratio: 1.25;
--base: 1rem;
}
模块化比例的关键决策是"选多大的比例"。经验法则是:信息密度越高,比例越小。后台管理系统、数据看板这类界面,正文与标题差距不宜过大,1.125~1.2 更合适;而博客、官网这类以阅读和视觉冲击为主的页面,可以用 1.25~1.333。使用 1.618 黄金比例时要格外谨慎,因为三级标题之后字号会迅速膨胀,很容易导致标题在移动端占满整屏。
另一个实用技巧是移动端使用更小的比例。桌面端 1.25 的效果是 h1 比正文大 2.4 倍,这个差距在 1440px 宽度下很舒服;但在 375px 宽度下,2.4 倍的标题会占据过多纵向空间,导致用户第一屏看不到正文。因此在移动端把比例降到 1.125~1.2,是常见的优化手段。
响应式行高、字距与段落间距
字号只是排版的一半,另一半是"呼吸感"。行高、字距、段落间距这些参数如果固定不变,即使字号做了流体处理,整体观感依然会失调。
核心规律是:字号越大,行高比例应越小;字号越小,行高比例应越大。这是因为大字号本身的行间空白已经足够,过大的行高会让标题显得松散、失去整体感;而小字号则需要更大的行高来引导视线横向移动,避免跳行。
h1 {
font-size: clamp(1.75rem, 1rem + 3.2vw, 3.5rem);
line-height: 1.1;
letter-spacing: -0.02em; /* 大字号收紧字距 */
}
/* 正文:行高 1.6 ~ 1.75 是舒适区间 */
p {
font-size: clamp(1rem, 0.95rem + 0.25vw, 1.15rem);
line-height: 1.7;
letter-spacing: 0.01em;
}
/* 小字号:行高放开,字距略增 */
small, .caption {
font-size: 0.8rem;
line-height: 1.75;
letter-spacing: 0.02em;
}
/* 段落间距:用 em 与字号联动 */
p + p {
margin-top: 1.2em;
}
/* 标题上方的留白应大于下方(亲近性原则) */
h2 {
margin-top: 2.2em;
margin-bottom: 0.7em;
}
/* 用 clamp 让行高本身也流体化 */
p {
line-height: clamp(1.55, 1.4 + 0.5vw, 1.8);
}
字距(letter-spacing)的处理容易被忽视,但对中文与西文混排的页面影响很大。基本原则是:大字号收紧(负值)、小字号放宽(正值)、正文接近 0。原因是字体设计师在设计字形时,通常以正文字号为基准优化间距;当字号被放大时,字间距会显得过大,需要手动收紧;当字号缩小时,字形细节拥挤,需要略微放宽来提升辨识度。
段落间距方面,建议使用 em 而非固定像素,这样它就能随字号自动缩放。p + p { margin-top: 1.2em } 这种写法既避免了首段多余留白,又保证间距与字号比例恒定。另外,标题的上下留白应该遵循"亲近性原则"——上方的间距应明显大于下方,这样标题才会在视觉上归属于它下面的内容,而不是上面的段落。
行长控制:阅读体验最被低估的变量
如果只能优化一个排版参数,我会毫不犹豫地选择"行长"。研究表明,西文的最佳行长约为 45~75 个字符,中文由于字符宽度一致且信息密度更高,最佳行长约为 25~40 个汉字。行长过短会导致换行过于频繁、阅读节奏被不断打断;行长过长则会导致回扫困难,读者读完一行后很难准确找到下一行的起始位置。
.article-body {
width: 100%; /* 在 2560px 屏上行长可达 200+ 字符 */
}
/* 正确:用 ch 约束行长,并居中 */
.article-body {
max-width: 68ch;
margin-inline: auto;
}
/* 中文内容可用 em 约束(1em ≈ 1 个汉字宽度) */
.article-body--zh {
max-width: 36em; /* 约 36 个汉字 */
}
/* 用 min() 让行长随视口收缩,但不超过上限 */
.article-body {
max-width: min(68ch, 100% - 2rem);
}
/* 侧边栏/窄栏中的文本用更小的行长 */
.sidebar p {
max-width: 45ch;
}
/* 代码块、表格允许更宽 */
pre, table {
max-width: 100%;
overflow-x: auto;
}
值得注意的是,行长的约束对象应该是"文本容器"而不是"整个页面"。一个常见的错误是给 body 设置 max-width,结果导致全站所有内容都被限制在同一宽度里,图片、视频、宽表格也跟着变窄。正确的做法是把行长约束交给具体的文本容器(如 .article-body、.prose),让其他元素仍能利用完整宽度。
另外,在多栏布局中,每一栏都应该独立满足行长要求。如果你把桌面端的两栏布局在平板上直接变成单栏,那么原本每栏 40ch 的文本会突然变成 80ch,阅读体验反而下降——这也是为什么响应式排版不能只靠"列数变化"来解决。
用 CSS 自定义属性构建排版令牌系统
当项目规模变大,散落各处的字号、行高、间距会迅速失控。解决方案是建立"排版令牌"(Typography Tokens)——用 CSS 自定义属性把排版决策集中到一处,组件只消费变量,不写具体数值。
:root {
/* 字体族 */
--font-sans: 'Noto Sans SC', system-ui, sans-serif;
--font-serif: 'Noto Serif SC', Georgia, serif;
--font-mono: 'JetBrains Mono', monospace;
/* 字重 */
--fw-regular: 400;
--fw-medium: 500;
--fw-bold: 700;
/* 字号音阶(流体) */
--fs-xs: clamp(0.75rem, 0.72rem + 0.15vw, 0.8rem);
--fs-sm: clamp(0.875rem, 0.84rem + 0.2vw, 0.95rem);
--fs-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
--fs-lg: clamp(1.125rem, 1rem + 0.6vw, 1.35rem);
--fs-xl: clamp(1.3rem, 1rem + 1.4vw, 1.75rem);
--fs-2xl: clamp(1.6rem, 1rem + 2.4vw, 2.4rem);
--fs-3xl: clamp(1.9rem, 1rem + 3.6vw, 3.2rem);
/* 行高 */
--lh-tight: 1.15;
--lh-snug: 1.35;
--lh-normal: 1.6;
--lh-relaxed: 1.75;
/* 字距 */
--ls-tight: -0.02em;
--ls-normal: 0;
--ls-wide: 0.03em;
}
改一处,全站生效
建立令牌系统时,建议分成三层:基础令牌(原始数值,如 --fs-base)、语义令牌(表达用途,如 --text-body、--text-caption)、组件样式(只消费语义令牌)。这样当设计规范调整时,你只需要改动语义令牌的映射关系,而不必去每个组件里搜索替换。
:root {
--text-display: var(--fs-3xl);
--text-heading: var(--fs-2xl);
--text-subheading: var(--fs-xl);
--text-body: var(--fs-base);
--text-caption: var(--fs-sm);
--text-footnote: var(--fs-xs);
}
/* ---------- 3. 组件消费层 ---------- */
.card__title {
font-size: var(--text-subheading);
line-height: var(--lh-snug);
letter-spacing: var(--ls-tight);
}
.card__body {
font-size: var(--text-body);
line-height: var(--lh-normal);
}
可变字体:一个文件承载整套字重与字宽
传统字体需要为每个字重单独加载一个文件(Regular、Medium、Bold……),而可变字体(Variable Fonts)把整个设计空间压缩进一个文件,通过 font-variation-settings 或标准的 font-weight 等属性连续调节。这不仅节省带宽,更让"字重随屏幕变化"成为可能。
@font-face {
font-family: 'InterVariable';
src: url('fonts/inter-var.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: swap;
unicode-range: U+0000-00FF, U+4E00-9FFF;
}
/* 字重随屏幕变化:小屏更重,大屏更轻 */
body {
font-weight: 450;
}
@media (max-width: 480px) {
body { font-weight: 480; } /* 小屏加粗一点更清晰 */
}
/* 光学尺寸:让字体在不同字号下自动优化细节 */
body {
font-optical-sizing: auto;
}
/* 手动微调可变轴(谨慎使用) */
h1 {
font-variation-settings: 'wght' 720, 'opsz' 48;
}
/* 字体加载优化:先显示系统字体,再替换 */
@font-face {
font-family: 'Noto Sans SC';
src: url('fonts/noto-sans-sc.woff2') format('woff2');
font-display: swap;
size-adjust: 100%; /* 调整回退字体视觉大小 */
}
可变字体在响应式排版中的价值主要体现在两点。第一是字重微调:在低分辨率的小屏幕上,稍微加粗正文(如从 400 调到 450~480)能显著提升清晰度;而在高分辨率大屏上,稍轻的字重会显得更精致。第二是光学尺寸(opsz):许多可变字体内置了光学尺寸轴,字体引擎会在大字号下自动收紧字距、加细笔画,在小字号下加宽字距、加粗笔画——这正是传统金属活字时代的智慧,如今由字体文件自动完成。
使用可变字体时务必注意性能。中文字体文件动辄数 MB,直接引入会严重拖慢首屏。建议做法是:子集化(只保留用到的字符)、使用 unicode-range 分片加载、设置 font-display: swap 避免阻塞渲染,并配合 size-adjust 让回退字体的视觉大小与目标字体接近,减少字体切换时的布局跳动(CLS)。
现代 CSS 文本排版特性
近几年 CSS 在文本排版领域新增了大量实用特性,它们能显著提升排版质量,且大多已被主流浏览器支持。
h1, h2, h3 {
text-wrap: balance;
}
/* 2. 正文换行更美观,避免最后一行只剩一个词 */
p {
text-wrap: pretty;
}
/* 3. 长单词/URL 自动断行 */
.article-body {
overflow-wrap: break-word;
word-break: normal;
}
/* 4. 连字符(西文长词排版) */
.article-body {
hyphens: auto;
-webkit-hyphens: auto;
}
/* 5. 中文标点与西文间距优化 */
.article-body {
text-spacing-trim: space-all;
text-autospace: normal;
}
/* 6. 数字等宽,表格对齐更整齐 */
.stat-number {
font-variant-numeric: tabular-nums;
}
/* 7. 首字下沉(杂志风) */
.article-body > p:first-of-type::first-letter {
float: left;
font-size: 3.2em;
line-height: 0.9;
margin-right: 0.08em;
}
/* 8. text-box-trim:精准裁掉行高空隙 */
h2 {
text-box: trim-both cap alphabetic;
}
1,234.56
1,234.56
text-wrap: balance 和 text-wrap: pretty 是近年来最实用的排版增强。balance 会让多行标题的每行长度尽量接近,消除"最后一行只剩一个字"的尴尬;pretty 则主要优化段落最后一行的断行质量。不过要注意,balance 目前对行数有限制(通常是 6 行以内),所以更适合标题而非长正文。
对于中文排版,text-autospace 和 text-spacing-trim 尤其值得关注:前者能在中文与西文、数字之间自动插入适当间距,后者则能裁掉中文标点符号左右两侧多余的空隙,让段落边缘更加整齐。这两个特性目前支持度还在推进中,但可以作为渐进增强使用。
text-box-trim 解决的是一个长期困扰前端的老问题:文本行高带来的上下空白会让标题看起来"位置不对",即使你设置了正确的 margin,视觉上仍然偏移。这个属性可以直接裁掉行高的上下空隙,让间距控制真正精确到字形边缘。
无障碍与用户偏好适配
响应式排版不只是"适配屏幕",更要"适配人"。用户的视力状况、阅读习惯、系统设置千差万别,一个成熟的排版系统应当尊重这些差异。
html {
font-size: 100%; /* 跟随浏览器设置 */
}
/* 2. 保证正文对比度符合 WCAG AA(≥ 4.5:1) */
body {
color: #1e293b; /* 不要用纯黑 #000 */
background: #ffffff;
}
/* 3. 深色模式下的排版调整 */
@media (prefers-color-scheme: dark) {
body {
color: #e2e8f0;
background: #0f172a;
font-weight: 380; /* 浅色字在深底上显得更粗,略减 */
line-height: 1.75;
}
}
/* 4. 高对比度偏好 */
@media (prefers-contrast: more) {
body { color: #000; }
a { text-decoration: underline; }
}
/* 5. 尊重用户的字体族选择 */
.article-body {
font-family: var(--font-sans);
}
/* 部分用户会设置"强制使用系统字体",不要对抗它 */
/* 6. 动态字号适配(大字模式) */
@media (min-width: 1px) {
/* 用 em/rem 布局,用户放大字号时布局自动撑开 */
}
/* 7. 保证 200% 缩放下的可用性 */
/* 不要用固定高度 + overflow:hidden 截断文字 */
.card {
min-height: 120px; /* 用 min-height 而非 height */
}
这里有一个容易被违反的原则:永远不要用 user-scalable=no 或 maximum-scale=1 禁止用户缩放。虽然这看起来能"保护设计稿",但它直接剥夺了低视力用户放大阅读的权利,属于严重的无障碍缺陷。正确的做法是通过合理的流体排版让用户"不需要缩放",而不是"禁止缩放"。
另外,正文颜色不建议使用纯黑 #000。在白色背景上,纯黑文字对比度极高,长时间阅读容易产生视觉疲劳甚至残影感。使用 #1e293b、#1f2937 这类接近黑色的深灰,对比度仍在 12:1 以上(远超 WCAG AA 的 4.5:1 要求),但观感更柔和。深色模式下则相反,避免使用纯白 #fff,用 #e2e8f0 这类浅灰更舒适。
排版调试与测试方法
排版是"感受型"的,很难靠肉眼在单一屏幕上判断好坏。以下方法能帮助你在开发阶段就发现排版问题。
@media (min-width: 1px) {
.debug-typography p {
outline: 1px dashed rgba(37, 99, 235, 0.35);
background: rgba(37, 99, 235, 0.03);
}
}
/* 方法 2:显示当前断点标签 */
body::after {
content: "XS < 480px";
position: fixed;
bottom: 10px;
left: 10px;
background: rgba(15, 23, 42, 0.85);
color: white;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-family: monospace;
z-index: 9999;
}
@media (min-width: 768px) {
body::after { content: "MD ≥ 768px"; }
}
@media (min-width: 1024px) {
body::after { content: "LG ≥ 1024px"; }
}
/* 方法 3:用 CSS 统计当前行长 */
/* 结合 JS 可在控制台输出实际字符数 */
/* const el = document.querySelector('p');
const w = el.clientWidth;
const fs = parseFloat(getComputedStyle(el).fontSize);
console.log('约 ' + Math.round(w / fs) + ' 个汉字/行'); */
测试排版时,建议至少覆盖以下几个宽度:320px(最窄主流手机)、375px(iPhone 常见宽度)、768px(平板竖屏)、1024px(平板横屏/小笔记本)、1440px(主流桌面)、1920px 和 2560px(大屏)。在每个宽度下检查三件事:正文是否清晰可读、行长是否舒适、标题与正文的层级是否分明。
此外,一定要在真实设备上测试。模拟器无法完全还原真实设备的字体渲染(尤其是中文字体的 Hinting 与字重表现)、DPI 缩放和系统字号设置。如果你在模拟器上看到的 16px 中文很清晰,在真实手机上可能因为字重偏细而显得发虚——这时候就需要用可变字体微调字重,或者换用更适合小字号显示的字体。
响应式排版最佳实践与总结
- 字号用 rem,间距用 em,行长用 ch:让每个单位发挥它最擅长的作用
- 流体优先,断点为辅:用
clamp()处理连续变化,用媒体查询处理结构性变化 - 字号最小值不低于 16px:这是移动端正文可读性的经验底线
- 行长控制在 45~75ch:中文可适当收窄到 30~40 个汉字
- 大字号收紧行高与字距,小字号反之:这是排版最基本的视觉规律
- 建立三层令牌系统:基础令牌 → 语义令牌 → 组件消费,让调整集中可控
- 尊重用户偏好:不禁止缩放,用 rem 响应浏览器字号,适配深色模式与高对比度
- 字体性能不可忽视:子集化、
font-display: swap、size-adjust减少布局偏移 - 用真实设备验证:模拟器只能覆盖 80% 的情况
- 渐进增强:新特性(
text-wrap、text-box-trim)作为增强而非依赖
:root {
/* 音阶 */
--fs-xs: clamp(0.75rem, 0.72rem + 0.15vw, 0.8rem);
--fs-sm: clamp(0.875rem, 0.84rem + 0.2vw, 0.95rem);
--fs-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
--fs-lg: clamp(1.125rem, 1rem + 0.6vw, 1.35rem);
--fs-xl: clamp(1.3rem, 1rem + 1.4vw, 1.75rem);
--fs-2xl: clamp(1.6rem, 1rem + 2.4vw, 2.4rem);
--fs-3xl: clamp(1.9rem, 1rem + 3.6vw, 3.2rem);
/* 行高 */
--lh-tight: 1.15;
--lh-snug: 1.35;
--lh-body: 1.7;
/* 行长 */
--measure: 68ch;
--measure-zh: 36em;
}
body {
font-family: var(--font-sans);
font-size: var(--fs-base);
line-height: var(--lh-body);
color: #1e293b;
}
.prose {
max-width: min(var(--measure), 100% - 2rem);
margin-inline: auto;
}
.prose h1 {
font-size: var(--fs-3xl);
line-height: var(--lh-tight);
letter-spacing: -0.02em;
text-wrap: balance;
}
.prose p {
text-wrap: pretty;
overflow-wrap: break-word;
}
.prose p + p {
margin-top: 1.2em;
}
/* 中文内容微调 */
.prose--zh {
max-width: var(--measure-zh);
letter-spacing: 0.01em;
text-align: justify;
text-justify: inter-ideograph;
}
结语
响应式排版不是一堆技巧的堆砌,而是一套"以阅读体验为中心"的思维习惯。当你开始用 clamp() 思考字号、用 ch 思考行长、用令牌思考一致性、用无障碍思考包容性时,你写出的就不再是"能看的页面",而是"好读的页面"。
排版系统的价值在于:它让好的阅读体验可以被复用、被维护、被规模化。一个精心设计的排版令牌系统,能让团队里每个人写出的页面都保持一致的节奏感;一套完善的流体排版规则,能让你的内容在从 320px 到 2560px 的任何屏幕上都从容不迫。
最后送上一句话作为本文的收尾:用户记不住你的栅格,但会记住阅读时的感受。把排版做好,就是把内容真正交到读者手里。