中文网页看起来”不够精致”,通常不是字体不好看,而是几个细节没处理。这些处理成本都很低,但改完之后观感差别相当明显。
标点造成的空洞
中文全角标点自带左右空白,本意是保证在竖排和方格稿纸里对齐。但在网页上,连续出现的标点就会挤出一片空白:
他问:「你确定吗?」——我没答。
: 后面跟 「,两个全角字符各带半个字宽的空白,视觉上就是一个突兀的洞。
CSS 有个新属性专门处理这件事:
body {
text-spacing-trim: space-first;
}
它会裁掉开头标点的前置空白,让连排标点收紧。不支持的浏览器直接忽略,没有副作用,属于零成本的渐进增强。
不过目前浏览器支持还不完整,别指望它解决全部问题。真正要紧的排版位置——比如大字号标题——该手工调整还是得手工调整。
中西文之间的间距
「使用 Astro 构建」和「使用Astro构建」,后者读起来是要费点力的。
传统做法是在中西文之间手动加空格,或者上 pangu.js 这类库在运行时插入。但运行时插入意味着一段 JavaScript 参与了内容渲染,对于要求”禁用 JS 后页面仍完整”的站点来说不划算。
更轻的做法是接受”源文本里就写空格”这个约定。写作时在中英文之间敲一个空格,Markdown 原样保留,浏览器自然断行。这既是排版处理,也是可读的纯文本。
font-kerning: normal 也值得开——它让浏览器应用字体自带的字距调整表,对西文字母组合(比如 AV、To)效果明显,中文字体一般没有这张表,开了也不亏。
字体回退链
中文字体栈的写法有个常见错误:只写一个中文字体名就完事。
/* 不够健壮 */
font-family: 'Songti SC', serif;
问题是 Songti SC 只在 macOS 上有。Windows 用户拿到的是 serif 的系统默认值——通常是新罗马字体渲染中文,也就是宋体的某个替代品,效果不可控。
更稳的写法是把西文字体放在前面,中文字体依次列出各平台的名字:
--font-serif:
Georgia, /* 西文优先匹配,中文跳过 */
'Songti SC', /* macOS */
'SimSun', /* Windows */
'Noto Serif CJK SC', /* Linux / 思源宋体 */
serif;
浏览器按字符逐个查找:西文字符在 Georgia 里找得到,直接用;中文字符 Georgia 里没有,继续往后找。一份字体栈同时服务两种文字,这是 font-family 的正常工作方式,很多人以为它是”整体选一个”。
顺序不能反。如果把中文字体放前面,西文字符会优先用中文字体里的西文字形——那些字形通常是等宽的、为方格设计的,混排时会明显偏胖。
行高与行宽
中文没有西文那样明显的升部降部,同样行高下看起来更挤。西文正文 1.5 够用,中文建议给到 1.75 到 1.9。
行宽的经验值是每行 30 到 40 个汉字。用 ch 单位不太准——ch 是数字 0 的宽度,对中文没意义。直接用 em 更直观:
.wrap { max-width: 34em; }
34em 在 17px 字号下约等于 578px,一行差不多 34 个汉字。
一个小结
这些改动都很小,单独看都不起眼。但排版就是这样——没有哪一条能让页面”变好看”,是所有细节一起把粗糙感磨掉的。