中文标点前后那一格宽的空,你用负 margin 抠了十年——CSS 一个属性把它交给字体自己算了
中文页面里那一格莫名其妙的白,终于不用你手动抠了。
你有没有注意过这个细节:一段以中文引号「开头的正文,第一行总比后面几行往里缩进去大半个字的宽度;两个标点挨在一起的时候(比如……」或),中间会凭空多出一整格空白。这不是你的排版写坏了——是全角标点字形里天生自带的内部留白。
一个全角标点(、。,「」())为了跟汉字保持一致的宽度,字身框里留了等宽的空。单独出现时看不出来,一旦连续出现、或者出现在行首,这点留白就变成了肉眼可见的空洞。中文 web 排版讲了十几年,这个坑一直没被浏览器原生解决。
过去大家怎么修的
最常见的做法是手动塞负 margin,配合 text-indent 往左拽:
.prose p:first-letter { margin-inline-start: -.25em; }
.prose p { text-indent: -.25em; padding-inline-start: .25em; }
.prose q::before { margin-inline-start: -.2em; }
.prose q::after { margin-inline-end: -.2em; }
十几行 CSS,只为了处理”行首标点”和”相邻标点”两类情况。问题也很明显:内容一改就崩。段首换个字符、标点从行首挪到行中,之前算好的负值全部错位。更别说还要给每个引用、每个括号单独配一遍伪元素。有人在博客里吐槽过,这是”没有 API 能检测元素在视觉行中的位置”逼出来的土办法。
还有一派是直接改字体:用自定义标点字体给标点对做 kerning,或者把全角标点替换成半角标点 + 半宽空格。可靠,但要额外加载字体,还容易在选择文本时打断选区形状。
浏览器终于把这件事收编了
CSS 的 text-spacing-trim 属性,就是把这件事交给字体和浏览器自己决定。它根据字体的 OpenType 元数据(halt 或 chws 特性)来读取标点该挤多少,一行搞定:
.prose {
text-spacing-trim: trim-start;
}
几个取值,覆盖不同激进程度:
normal:默认。行首开标点保持全角,连续标点之间的空白会被折叠trim-start:行首的开标点收缩为半宽。最常用,解决第一行缩进问题space-first:只保留第一行的开标点全角,其余行收缩。适合某些标题场景space-all:所有全角标点都保持全角,相当于关掉挤压
想连行尾的收标点一起处理,规范里还定义了 trim-both / trim-all / auto,但目前没有浏览器实现,先别用。
注意一个前提:字体必须带 OpenType 的 Alternate Half Widths(halt)或 Contextual Half-width Spacing(chws)特性,否则 text-spacing-trim 会直接失效。好消息是主流中文字体(Noto Sans CJK、Source Han Sans 这类)基本都带。
现在的支持情况
数据来自 caniuse:全球约 72.71% 的用户已经能用上。Chrome / Edge 从 123 版(2024 年初)起默认支持,Chrome for Android、Android Browser 都已跟上。但 Safari 全系不支持(3.1 一直到当前 27 / TP 都没有),Firefox 也一直没实现——所以它还不是 Baseline 特性,不能无脑上。
这意味着现在的最佳姿势是渐进而非替换:保留你原来的负 margin 兜底逻辑,同时把 text-spacing-trim 加进去,支持它的浏览器走原生,不支持的继续用老代码。等 Safari 跟上再把 hack 删掉。
可以落地的下一步
- 先给正文容器加一行
text-spacing-trim: trim-start;,肉眼对比行首缩进是否消失 - 确认你的中文字体带 halt / chws 特性(用 FontTools 查一下,或者直接看效果有没有生效)
- 代码块、等宽字体区域记得关掉:
pre, code { text-spacing-trim: space-all; },不然标点会被挤得不像代码 - 别忘了给页面根节点标
lang="zh-CN"——浏览器要靠语言标注来判定走哪套行首尾规则和断行规则,没标 lang 的情况下部分行为不生效
顺带提一句,同一个 CSS Text 模块里还有个 text-autospace,负责中西文之间的自动间距(中文和 English 之间自动生成 1/4 空格)——和 text-spacing-trim 是一对。以前靠 pangu.js 做后处理的年代,2026 年算是正式翻篇了。
一句话结论:全角标点自带的那点内部留白,不只是视觉洁癖——它直接影响中文页面的首行对齐和阅读节奏。现在有一行 CSS 能管,先用渐进增强的方式加进去,不会亏。
评论区
登录后可评论。