系列:博客工程实践
- 代码高亮从手写到 Expressive Code 的改造记录
- 用 Playwright 给静态博客做视觉回归测试
一开始这个博客的代码块样式是手写的:给 pre 加背景、边框和横向滚动,再给 code 做一点重置。能看,但不够像一个认真写教程的站点。
真正让我决定改掉它的原因有几个:代码没有稳定的语法高亮,没有文件名标题栏,没有复制按钮,也没有行号和重点行。教程文章越写越多后,这些功能就不是装饰了,而是阅读体验的一部分。
手写代码块的问题
手写样式通常只能做到这个程度:
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 习惯,标题和重点行可以直接写在代码块信息里。
def hello(name: str): message = f"hello {name}" print(message)重点行可以直接写在代码块信息里,比在正文里说“注意第三行”更直观。
diff 样式很适合配置对比
写配置类文章时,diff 很有用。
DEBUG = trueDEBUG = false读者能一眼看到改了什么,不需要在两段配置之间来回对比。尤其是 Nginx、Docker Compose、Django settings 这类文章,diff 比普通代码块更适合说明修改点。
终端代码块要和普通代码区分
命令行代码块和源码代码块不是一类东西。源码关注结构和语法,终端命令关注可复制和执行顺序。
npm run check:contentnpm run build:guard我后来给终端块单独调了标题栏和背景层次,但保留了一个原则:浅色主题下不能为了“像终端”强行压暗背景,否则 token 颜色对比度会出问题。这个问题后来是通过无障碍测试发现的。
迁移时踩过的点
第一类问题是复制按钮文案。默认文案不一定适合中文博客,所以需要把提示改成中文。
第二类问题是深浅色同步。页面切换主题后,如果代码块没有同步,看起来会像嵌了一块别的网站的内容。
第三类问题是构建警告。内容检查允许的语言,不代表高亮器一定认识。比如某些配置语言最后要改成 text,避免构建日志里出现高亮降级警告。
怎么验证改造结果
我不只看页面是否能打开,还会检查这些点:
- 代码块是否有标题栏
- 复制按钮是否存在
- 行号是否显示
- 高亮行是否可见
- diff 增删行是否有样式
- 终端块是否有独立视觉
- 深浅色切换后背景是否同步
- 无障碍检查是否报颜色对比度问题
这些验证已经放进浏览器 smoke 测试里。视觉相关的变化也会走截图回归,避免以后改 CSS 时把代码块样式改坏。
这部分可以接着看 用 Playwright 给静态博客做视觉回归测试,它更偏向怎么把这些检查放进日常发布流程。
总结
代码高亮不是“文章好不好看”的小问题。对技术博客来说,代码块是正文的一部分,尤其是教程和排障文章。手写样式适合起步,但当文章越来越多,使用成熟的代码块渲染方案会更稳。
这次迁移最大的收益不是颜色更漂亮,而是写作格式变清楚了:文件名、重点行、diff、终端命令都能用统一方式表达。后面写文章时,解释成本会低很多。