← 返回首页

排版的艺术:一条很长很长的路

排版是门技术活,这不用多说。

漫漫长路, Markdown, 大乱斗

观前提示

本文中为了展示大量的、或好或坏的排版,插入了很多图片。尽管现在的浏览器会聪明地使用懒加载,但我仍然推荐你在 Wi-Fi 环境下阅读,毕竟移动数据是越来越贵了。

还有,如果一边照着本文一边翻 Mozilla 的 CSS 文档,阅读体验会好一些。这儿有中文版

号外!

开了个新坑,就叫做漫漫长路,这里写杂记和思考。

小小的 leading

我的博客经历了若干次重构,从一开始用 Hexoicarusamazing 主题,再到后来看了不少 Hexo 的坏话1,渐渐地坚定了迁移的决心。然后换到了 Astro,就是那个黑白配色,以排版为主要特色的博客主题(不然它也不会胸有成竹地管自己叫做 Retypeset)。最后,也就是你看到的这个,是用 Hugo2一点一点打出来的,设计 CSS 用上了我关于排版的一生所学。

重构,排版。设计博客样式时,这两兄弟大概是最离不开的字眼。头一个就不说了,太磨人。我要说的是第二个:明明简单却总是被人搞得如同地狱一样的排版(Typography)

肯定有维新派叫嚷着:

Protip!

2026 年了,还写什么博客?这种老掉牙的东西就应该丢进历史的垃圾堆!我都到微信公众号去写了!

但你写微信公众号推文总要在乎排版吧?但我这里不是要教你怎么给推文排版,因为优秀的排版都是相通的,并不是像公众号里边营销号吹的那样,只有带 qq 两个字的网页才能用。

排版真难……对吗?

糟糕的排版

废话少说,直接看一个。

_image

一个人点进来这个网站,结果第一印象是:我到底要看什么?

这种排版就是失败的。那还有一个问题:失败在哪儿?

排版的目的,就是要让读者马上意识到我是来干什么的,是读文档也好,是看点作品集也罢,哪怕只是随意地读一读碎碎念,视线落下来的第一秒,读者的心里就要想:“喔,重点在这里”。

上面的排版,失败之处就在于字太小、分隔不清、图片和代码块喧宾夺主,正文像个被排挤的临时工。3

_image

这是 LINUX DO 社区的早期 UI,我管这种 UI 叫做“高额头和宽下巴”。

我的网站只放了萌备,因此效果不算恶劣。如果这种排版被幸运地在你的博客上展示,它会毁了你的博客:点进一个内容驱动型网站,必须要忍受这么破碎的信息,脾气好的读者可能跑路了事,脾气差点的直接找上评论区开骂了。

优秀排版和你

优秀排版的纲要显而易见:

上面两个排版,之所以糟糕,就是因为看着太叫人窒息了。

虽然这份我自己总结出的纲要只有短短十二字,但是要实现它的确不容易。排版如果只是单纯的技术问题或者美学问题就好了,可惜它不是。

内容为王·王也要穿衣服

我们这里并不是在说安徒生的童话。曾有一位智者这样说过——

智者的箴言

好的排版会让你的文章变得更好,哪怕文章的内容只是一坨大便。

其实文章的内容不是一坨大便也行。世界级名著《提问的智慧》4,它的作者埃里克·斯蒂芬·雷蒙把这旷世神作发到个人网站上时也没有写任何样式。5

当然会有别扭精秉承着“这可是名著!😡”的精神生啃。但我们是普通人,看这玩意会觉得很头大,不是吗?你要是用电脑看的话,十有八九会蹦出一个疑惑🤔:“我刚刚是不是看到这一行了?”更叫人挠头的是,原文是英文。

但是,在 GitHub 上的版本因为有完善的样式表,读起来简单轻松许多。对比看看?这和中英文没有太大关系。

GitHub 上的《提问的智慧》
GitHub 上的《提问的智慧》

读得开心多了吧?

不过也别想着马上兴高采烈地用 github-markdown-css 来给自己的网站上样式——你得照着自己网站的个性来。还有最重要的:你得喜欢你用的样式。写了一篇好玩的游记,读者还要在一个长得神似 GitHub 的网站看,这也太可怜了。

当然,如果你嫌麻烦,Tailwind CSS 提供的 @tailwindcss/typography,以及 Sivan 开发的赫蹏可能更适合你,这玩意足够大众,技术文档到生活日志全部通吃。

当年汉字排版还在搞活字印刷术、西文排版还在纠结 fiti 怎么连字的时候,排版就是拼拼图。但咱们今天有那么多的 CSS 属性,反而都不会排版了。没有内容的排版是空壳。你选再漂亮的字体、再精致的留白,如果读者读完三分钟不知道你在说什么,那就是失败。这也是为什么很多人信奉“内容为王”——只要我写得好,其他不重要。但是,王也需要穿衣服。裸奔的国王走到街上,无论他多有智慧,大伙儿第一反应都是“这个人没穿衣服”。

要吐槽还能写一堆,按下不表。

字体·丢掉你的 LXGW

看到这标题千万别皱眉。LXGW WenKai,也就是霞鹜文楷,用来排版长文跟在厕纸上印刷泰戈尔诗集没什么区别:可以看,但是看得很别扭。所以,放过它吧。

这个字体又开源,又文艺青年,还有手写的提按,哪里有问题?

问题就在这,它太吵了。LXGW 的笔画粗细太明显,确实很有楷书的顿挫和毛笔的飞白,单看几个字很漂亮,但是放到长文里就成了夹生饭。它既不是黑体字,也不是楷体字,一眼扫过去磕磕绊绊的。

这是前端大佬 Dnzzk2 的博客,很抱歉直接拿来当反例了
这是前端大佬 Dnzzk2 的博客,很抱歉直接拿来当反例了

字体就是空气,没人想在呼吸的时候被迫分辨空气的味道。所以,字体老老实实地选用默认的无衬线体(苹方、Inter、Noto Sans),要是想模拟英语课本你就用 Times New Roman。

下面的一些小短文使用了 <div> 标签结合内联样式展示不同的字体,从上往下依次是 Times New Roman、宋体(SimSun)和楷体(KaiTi)。为了避免太乱它们已经被折叠起来。

展开
Intro to ls

The ls command is one of the most essential tools in Linux and Unix-like systems. It lists the contents of directories, allowing you to see files, subdirectories, and their details at a glance. Whether you’re navigating the file system or checking permissions, ls is the first step.

Running ls by itself shows the contents of the current directory. You can also specify a path, like ls /home/user/Documents. To reveal more information, add options: -l provides a long listing with permissions, owner, size, and modification time; -a includes hidden files (those starting with a dot); and -h makes sizes human-readable when used with -l, showing values like 1K, 234M, or 2G.

Other useful flags include -t to sort by modification time, -r to reverse the order, and -R to list directories recursively. For instance, ls -ltr shows files sorted by time with the newest at the bottom, which is handy for finding recent changes. Many systems alias ll to ls -l for convenience. With color-coded output enabled by default on most distributions, ls instantly distinguishes files, directories, and executables. Simple yet powerful, mastering ls is the foundation of working confidently on the command line.

Simple use of Cron
Cron is a built-in time-based job scheduler in Linux and other Unix-like systems. It runs commands or scripts automatically at specified times or intervals, making it ideal for backups, system updates, and routine maintenance.

Each user can manage their own scheduled tasks using the crontab command. To create or edit your jobs, run crontab -e. To view existing entries, use crontab -l, and crontab -r removes all your cron jobs. A crontab line contains five time fields followed by the command to execute. The fields represent minute (0–59), hour (0–23), day of month (1–31), month (1–12), and day of week (0–7, where 0 and 7 both mean Sunday). An asterisk (*) matches every possible value.

For example, 0 2 * * * /home/user/backup.sh executes the backup script daily at 2:00 AM. You can also use commas for lists, hyphens for ranges, and slashes for steps (e.g., */5 * * * * runs every five minutes). System-wide jobs are often stored in /etc/crontab or the /etc/cron.* directories. Cron logs can be checked via /var/log/syslog or journalctl. With its straightforward syntax, cron makes task automation simple and dependable.

Vim 的前世今生
Vim 编辑器的故事,要从上世纪七十年代说起。加州大学伯克利分校的比尔·乔伊(Bill Joy)在开发 Unix 系统的过程中,先写了行编辑器 `ex`,又为它增加了一个“可视化”模式,这便是 1976 年诞生的 `vi`。vi 凭借极简的按键操作和高效的编辑哲学,迅速成为 Unix 世界的标配工具,但也因为缺乏多级撤销、语法高亮等现代功能,让不少用户既离不开它,又渴望更多。

1988 年。荷兰程序员布莱姆·米勒(Bram Moolenaar)想在刚买的 Amiga 电脑上使用 vi,却发现只有一款名为 STEVIE 的克隆品,且缺失了许多常用命令。于是他从 STEVIE 的源代码出发,不断打磨修复,于 1991 年正式发布了第一个公开版本——Vim 1.14。最初,Vim 代表“Vi IMitation”(vi 模仿者),随着功能的快速超越,很快被重新定义为“Vi IMproved”(vi 改进版)。

Vim 的进化轨迹非常清晰:2.0 带来了多级撤销;3.0 支持多窗口分割;4.0 首次引入图形界面;5.0 加入了语法高亮;6.0 则有了代码折叠、多语言支持与强大的插件体系。到了 2006 年发布的 7.0,拼写检查、代码补全、标签页等现代编辑器的标配功能一应俱全,Vim 也彻底从“vi 的小小增强”蜕变为一个高度可扩展的文本编辑平台。2016 年的 8.0 版本,终于加入了异步任务、内置终端等特性,解决了长久以来的性能束缚。

在 Vim 的发展中,有一段格外温暖的插曲。布莱姆是 ICCF 荷兰(一家乌干达儿童救助机构)的长期志愿者,他决定将 Vim 以“慈善软件”的形式发布,鼓励用户向乌干达儿童捐款,而不是向他付费。这个传统延续了几十年,直到 2023 年布莱姆因病去世,社区继续维护 Vim,且至今仍保留着对乌干达儿童的捐款提示。

此外,由于 Vim 代码库年久臃肿,2014 年部分开发者分叉出 Neovim,着力重构架构、引入现代化的异步与嵌入接口,如今已成为 Vim 生态中最活跃的分支。但在无数系统管理员、开发者和极客的心中,在终端里敲下 vim 的瞬间,仍是通向那个高效、纯粹编辑宇宙的大门。

《百年孤独》节选 - 加西亚·马尔克斯
“奥雷里亚诺,”他悲伤地敲下发报键,“马孔多在下雨。”

线路上一阵长久的沉默。忽然,机器上跳出奥雷里亚诺·布恩迪亚上校冷漠的电码。

“别犯傻了,赫里内勒多,八月下雨很正常。”

好的字体就像空气一样。现在几乎所有的中文图书都使用黑体和宋体进行排版,就是这个道理。不过即使它们优秀,不同的分支间亦有差异,就例如,思源宋体的横画非常的浅,白底黑字的情况下汉字的横几乎消失。

你要是不会选字体,就老老实实地用微软雅黑或者苹方。

.markdown {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "PingFang SC", "Microsoft YaHei", sans-serif;
}
Tip

宋体和楷体并不适合网页排版,它们的细节在网页上会被大量的锯齿替代,丢失掉原来的美感。如果为了美观我更推荐思源黑体 CJK,它专门对中文标点做了优化,例如引号和逗号、句号之间的间距。

颜色·别只会用黑白胶卷

爱画画的人可能听过这样一句理论:“给草稿勾线时,千万不要用纯黑色,而是用深蓝色或者红棕色。”我看的入门教程都没给出这样做的理由。但也很好理解:黑色在图画里是黑洞,它会吸引走人的注意力,而且不给反馈。

网页也是一样,单调的黑白,就好比 bearblog 那种黑白风格,极简确实极简,但是看了直叫人一阵空虚。好的配色应该灵动一点,别什么反馈都没有。

对了,我在配色时喜欢先选取主色调,然后排 CSS 变量,以后无论要用什么颜色直接从变量里挑选,就不另外硬编码 Hex 颜色了。6

:root {
  color-scheme: light dark;
  --bg: #f3eee8;
  --text: #1f2937;
  --heading: #1a1a1a;
  --muted: #6b7280;
  --meta: #6b6b6b;
  --subtle: #9ca3af;
  --accent: #517ad1;
  --accent-soft: #4c7bdf;
  --surface: #f8f4ef;
  --line: #d2c7bc;
  --inline-code-bg: #ece4dc;
  --code-bg: #172033;
  --selection: #c4826f47;
  --tag-pill-bg: #eee6de;
  --tag-pill-border: #d2c7bc;
  --tag-pill-text: #2b211d;
  --tag-pill-hover-bg: #e7ddd4;
  --tag-pill-hover-border: #c6b9ac;
  --tag-pill-hover-text: #241b17;
  --tag-pill-active-bg: #e1d6cc;
  --tag-pill-active-border: #bbac9e;
  --tag-pill-active-text: #1f1713;
  --focus-ring: #9db5e8;
  --scrollbar-track: #ece4dc;
  --scrollbar-thumb: #c8b9ab;
  --scrollbar-thumb-hover: #bbaa9a;
  --scrollbar-thumb-active: #ad9b8b;

  --font-title: "Noto Serif SC", "Source Han Serif SC", "Songti SC", "STSong", "Georgia", "Times New Roman", serif;
  --font-body-zh: "Noto Sans SC", "Source Han Sans SC", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  --font-body-en: "SN Pro", "SF Pro Text", "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Fira Code", "JetBrains Mono", "Cascadia Mono", "SFMono-Regular", "Consolas", "Liberation Mono", monospace;
}

还有一个暗色版的,节约篇幅就不贴了。

一旦选定颜色,就不要乱贴什么大红大绿的东西,特别是标题、链接这些地方。如果可以,把评论区的颜色也用 CSS 变量替换掉。应该说,现在百分之八十的 WordPress 主题都没有这样的认识,它们只是把博主可能感兴趣的全部粘上去,丝毫不考虑读者。但你要知道,开博客是要给读者看的,给自己看的还是别放到公网了。

配色就见仁见智了,通常也就是红橙蓝紫几位,绿色是大忌。有一些比较复古的(比如阮一峰)就用氧化后的纸的颜色做背景,也没有暗色模式,同样赏心悦目。

或者,比这哥们做得好就行。7

Warning
_image

配色人人都明白,无非就是让人看着舒服、一目了然,但是实际用上就知道有多吃审美眼光了。所以配色绝对不能太多,贪多嚼不烂,一个主色调就足够。网上说的撞色系、莫吉托,都是骗人的。

插个题外话,有个配色跟设计做的跟互联网厕所一样的博客,人气反而很旺。本来想作为反例放上来的,但是……我害怕后遗症,如果你也看过应该知道我在说什么。

间距·不要在夹缝中求生

Web 2.0 时代,谁也没想到会有 Vue、React 这些玩意,当时的网页就是一筒无限长的卷纸,一边扯一边看,像是把一本书的书页全部撕下,然后首尾相连粘起来。这样做的技术债就是,后来为了处理垂直居中,要花很大的力气。

咱们当然不用研究垂直居中,但跟它关系很大:我们要搞的是间距。没有任何一本书会忽略间距的设定,我在做我的网站时也是这样。

让我们回到 leading 部分。你不用动滚轮,下边有图片。

行距乱动
行距乱动

很明显吧?这里的行距是被脚注的数字顶开的,这就让字时起时落,很怪异。

但是,这样的问题还少吗?咱大可以先看点很叫人窒息的间距。

_image

这里一共(应该)有三个间距:

  1. 截图的边界和折叠块之间的间距。
  2. 折叠块边界和 blockquote admonition 之间的间距。
  3. blockquote 之间的间距。
  4. 段落之间的间距。

第二项和第三项都没有,看起来窒息那就是理所当然的了。

很多人喜欢在 CSS 里面加一个 text-align: justify;。不要这样做。中文是方块字,右端不对齐不会很明显,但是,换到英文里就变味了。

_image

里面用红线标注出的部分,叫做“文档的河流”。如果河流太多,人的注意力就会很快地涣散。所以不要自作聪明地加上两端对齐,直接用最原始的左对齐就好了。Microsoft Office Word 还有 LaTeX 都是这么干的,遵守它总不会被人笑话。

大致的图形搞定了,我们还漏了什么吗?当然有,那就是行间距和字重。

千万别吝惜行间距,该用就用。我读小学的时候,就有人告诉我每一段开头要空两格,但是网页里不能这样做。博客的段落是依靠行间距划分的,每一行顶格写都可以,不会导致两段的界限不清。

语文教材不同,里面文本的行间距就没变过,因此必须用分隔符来划分段落。HTML 不同啊,它可有 <p> 来告诉浏览器什么是段落。

如果你实在介意,CSS 里边有两个属性:text-indent(把它的值设成 2em 就是两个汉字的首行缩进)还有 text-autospace。你的空格要是没坏就手动在汉字和英文之间插个 space 吧,很简单的,最多按两下。

配角·滚出我的文档流

你肯定看过这种页面:侧边栏、跳转按钮、光标特效还有花里胡哨的页面背景。

还有!Live2D!Live2D!Live2D!我到底是来看文章的还是看小人乱动的?

nocilol.me
nocilol.me

还有太长的图片、代码块。拜托,假如不是非看不可就滚出我的文档流好吗?

如果你正在我的网站上阅读,页面中应该只有左侧的目录,其余部分全部被我赶走了。包括存在意义简直莫名其妙的侧栏 résumé,这些东西塞在 /about 页面就好,而且大多数人也不怎么感兴趣就是了。

在演示站中展示
在演示站中展示

因为灵感来源于 mediawiki 展示人物肖像,就直接拿来用,还管它叫做 mwfigure

啊!不对!这里怎么出现了一张莫名其妙的图片!

mediawiki 用了一种非常聪明的方法来处理这种不是主要内容,但是也不能删掉的非文档流内容,叫做破版(layout break)8,比如,我想告诉你这个破版的来源,但它跟我要写的排版关系没那么密切,就可以把它放在插图里。

它的问题也很明显,行为太不可预测,分分钟图片跳到下一段去了。不过比起被硬生生打断,还是好得太多。代码块……因为代码块常常是正文的一部分,所以我对于折叠代码或者移开它没有什么想法。毕竟是代码,图片,主次要分明。

还没完,总是有人搞出这种界面。

git.hust.cc/canvas-nest.js/
git.hust.cc/canvas-nest.js/

乱得没边了。

在后面

排版这东西,难看的大家都知道,但是做出来好的很难。因为优秀的排版就像是水,不会给人的阅读造成任何阻力。像个偏执狂一样,把行高从 1.625rem 调到 1.7rem,然后又调回去,如此反复。读者记得吗?当然不知道。但他们知道你的排版很好,好到读完时像是喝了一杯冰冰凉凉的可乐,没有任何阻力。

排版不是设计竞赛。所有的东西怎么打磨都是为了看见,打磨排版却是为了叫它消失。

(这一集很有教育意义)

每次看到沟槽的排版,我都有种拼命找出作者的邮箱然后给他发恐吓邮件的冲动。

但那没有用:不会排版还是不会排版。嘴臭留在自己的网站上就行。

时代在变,技术在变。排版很难,从头到尾都一样。但是,别在 line-height: 1.625margin-bottom: 1.25em 的死循环里纠结,有时候简单粗暴的 margin: 0.7rem 0.7rem 反而更有效。

祝你在接下来的日子里排得开心😄。

哦对,记得写博客,不写博客再好的排版都是废纸一张。

See Also

  1. 【Haku】我对各种字体的看法(Go 语言版)←我自己写的,在 IDE 里讨论了一个合适字体的重要性。
  2. 【纸鹿摸鱼处】谈谈不受欢迎的博客技术特征←句句见血,将讨人厌的博客网站特征全部点出来了,尽管不针对排版,还是值得一读。
  3. 【知乎】为什么海外杂志英文段落右端不对齐?←本文复制了其中的图片。

本文所展示的网页截图版权属于原作者,此处仅作为增强效果的工具。


脚注

  1. Hexo 早就不活跃了。它使用的已经是十年前的老古董 ejs 模板,从今天回看它也是太过于原始了。而且,更重要的是,它既笨重,又慢。 ↩︎

  2. Hugo 很好,真的。写 Hugo 的模板像 Go 语言一样优雅。哪怕是对于一个写习惯了 Python、不熟悉前端框架的人来说,Hugo 也足够友好。 ↩︎

  3. 好极了,这只是最突出的问题。这个排版的问题多了去了。 ↩︎

  4. How To Ask Questions The Smart Way。两个著名的缩写:STFW(Search the fucking web)以及 RTFM(Read the fucking manual)就是出自本文。 ↩︎

  5. 好极了,我不能在我的网站发原文的截图,因为它不是依赖 CC 协议发布的。 ↩︎

  6. Codex 这家伙老喜欢用 color-mix() 这种函数了……看着就惹人厌。 ↩︎

  7. 可喜可贺,我在 Reddit 上边找的演示,这哥们已经听人劝,改到了比较清新的风格。 ↩︎

  8. Layout break 在大多数语境下是恶性 bug,它会把在容器内排好的文本挤得到处都是。但我希望看到的是次要的内容被挤走,所以反而在这里用上了。 ↩︎

评论

支持两套评论系统,按需切换加载。