文章列表
4 分钟阅读

代码高亮从手写到 Expressive Code 的改造记录

更新说明:新增博客工程实践复盘文章。


系列:博客工程实践

第 1 / 2 篇

  1. 代码高亮从手写到 Expressive Code 的改造记录
  2. 用 Playwright 给静态博客做视觉回归测试

一开始这个博客的代码块样式是手写的:给 pre 加背景、边框和横向滚动,再给 code 做一点重置。能看,但不够像一个认真写教程的站点。

真正让我决定改掉它的原因有几个:代码没有稳定的语法高亮,没有文件名标题栏,没有复制按钮,也没有行号和重点行。教程文章越写越多后,这些功能就不是装饰了,而是阅读体验的一部分。

手写代码块的问题

手写样式通常只能做到这个程度:

global.css
pre {
padding: 1rem;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--surface-muted);
overflow-x: auto;
}
pre > code {
all: unset;
}

这段样式能解决基础显示,但解决不了结构问题。比如代码块里到底是什么语言,用户不知道;长教程里第几行是重点,也只能靠文字描述;需要复制命令时,用户还要手动选中。

这些问题在普通短文里不明显,但在 Docker、Nginx、FastAPI 这类教程里会反复出现。

为什么换 Expressive Code

我希望代码块至少支持这些能力:

  • 自动语法高亮
  • 标题栏显示语言或文件名
  • 复制按钮
  • 行号
  • 指定重点行
  • diff 的增删行样式
  • bash / shell 更像终端
  • 深浅色主题能同步

Astro 里接入 Expressive Code 后,这些能力基本不用自己维护。代码块写法也保持 Markdown 习惯,标题和重点行可以直接写在代码块信息里。

main.py
def hello(name: str):
message = f"hello {name}"
print(message)

重点行可以直接写在代码块信息里,比在正文里说“注意第三行”更直观。

diff 样式很适合配置对比

写配置类文章时,diff 很有用。

DEBUG = true
DEBUG = false

读者能一眼看到改了什么,不需要在两段配置之间来回对比。尤其是 Nginx、Docker Compose、Django settings 这类文章,diff 比普通代码块更适合说明修改点。

终端代码块要和普通代码区分

命令行代码块和源码代码块不是一类东西。源码关注结构和语法,终端命令关注可复制和执行顺序。

Terminal window
npm run check:content
npm run build:guard

我后来给终端块单独调了标题栏和背景层次,但保留了一个原则:浅色主题下不能为了“像终端”强行压暗背景,否则 token 颜色对比度会出问题。这个问题后来是通过无障碍测试发现的。

迁移时踩过的点

第一类问题是复制按钮文案。默认文案不一定适合中文博客,所以需要把提示改成中文。

第二类问题是深浅色同步。页面切换主题后,如果代码块没有同步,看起来会像嵌了一块别的网站的内容。

第三类问题是构建警告。内容检查允许的语言,不代表高亮器一定认识。比如某些配置语言最后要改成 text,避免构建日志里出现高亮降级警告。

怎么验证改造结果

我不只看页面是否能打开,还会检查这些点:

  • 代码块是否有标题栏
  • 复制按钮是否存在
  • 行号是否显示
  • 高亮行是否可见
  • diff 增删行是否有样式
  • 终端块是否有独立视觉
  • 深浅色切换后背景是否同步
  • 无障碍检查是否报颜色对比度问题

这些验证已经放进浏览器 smoke 测试里。视觉相关的变化也会走截图回归,避免以后改 CSS 时把代码块样式改坏。

这部分可以接着看 用 Playwright 给静态博客做视觉回归测试,它更偏向怎么把这些检查放进日常发布流程。

总结

代码高亮不是“文章好不好看”的小问题。对技术博客来说,代码块是正文的一部分,尤其是教程和排障文章。手写样式适合起步,但当文章越来越多,使用成熟的代码块渲染方案会更稳。

这次迁移最大的收益不是颜色更漂亮,而是写作格式变清楚了:文件名、重点行、diff、终端命令都能用统一方式表达。后面写文章时,解释成本会低很多。