代码高亮这件事,前端开发者再熟悉不过。从Highlight.js到PrismJS,从Rouge到Shiki,几乎每个技术博客都离不开它。但一位开发者最近受够了这些方案,自己动手写了一个名为MicroLighter的客户端语法高亮库,整个库压缩后只有约2kb,零依赖。

这个库的核心思路很直接:不再往DOM里塞一堆标签,而是用CSS Custom Highlights API来标记需要高亮的代码片段。这意味着代码块的DOM结构完全不被改动,高亮逻辑被压缩成两件事——用正则扫描代码块,然后调用CSS.highlights.set()把高亮范围交给浏览器渲染。

为什么不用span了?

传统高亮方案会在代码块里插入大量元素来包裹每个token,这既增加了DOM体积,也让样式控制变得繁琐。CSS Custom Highlights API提供了一种更干净的思路:通过::highlight(token-name)伪元素来定义高亮样式,把"高亮哪些token"和"怎么渲染"完全分开。

当然,这个方案也有自己的限制——::highlight()伪元素不支持斜体、加粗或字体切换。但除此之外,它用CSS来表达"我想高亮这个token"这件事,比到处插入span要优雅得多。

语言语法按需加载

MicroLighter的另一个设计决策是:所有语言语法都按需自动加载。作者经常在同一篇文章里混用HTML、CSS、JavaScript,偶尔还要加点bash、ruby和markdown。如果所有语言都打包进一个文件,体积会迅速膨胀。

为了解决这个问题,作者选择了Textmate的语言语法集合——就是VS Code在用的那套模式库。这样一来,MicroLighter几乎能支持任何语言,而且用户只需要为实际用到的语言付费(加载)。

主题合并:light-dark()一统明暗

代码块样式的一个常见痛点是:亮色主题和暗色主题是两套独立配置,维护起来很麻烦。MicroLighter用CSS的light-dark()函数把两套主题合并成一套,开发者只需要写一次主题变量,浏览器会根据当前配色方案自动切换。

此外,作者还借鉴了PrismJS的做法,把Textmate那种颗粒度很细的token分类压扁成更人性化的几类,让样式定制变得更直观。

高亮只做一件事,其他交给Web Component

MicroLighter的定位非常克制:只负责推断语言并高亮代码。像行号这类额外功能,被移到了一个独立的Web Component里。这个组件大约增加1kb的体积,但作者认为把UI逻辑封装进原生自定义元素里,配合ShadowDOM的隔离,能让代码和展示层彻底分开。

作者自嘲是个"Web Component爱好者",但在他看来,这种职责分离让整个方案更清晰:高亮库专注高亮,UI组件专注UI,两者互不干扰。

如果你也在为代码高亮的体积和灵活性纠结,这个项目提供了一个值得参考的新思路——用更现代的浏览器API,把高亮这件事做得更轻、更干净。