惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 三生石上(FineUI控件)
月光博客
月光博客
人人都是产品经理
人人都是产品经理
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
Vercel News
Vercel News
MyScale Blog
MyScale Blog
爱范儿
爱范儿
博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
H
Help Net Security
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
酷 壳 – CoolShell
酷 壳 – CoolShell
L
LangChain Blog
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
宝玉的分享
宝玉的分享
博客园 - 聂微东
云风的 BLOG
云风的 BLOG
J
Java Code Geeks
博客园 - 叶小钗
D
Docker

daverupert.com

I wish you the best in the Offline Shadow-piercing local component variables Vibe Check №43 Before I go: Double your business with companies you like The new yet familiar CodePen 2.0 Finding curated public domain images A workaround for hiding empty slots in Chromium Spoons by Sam Vibe Check №42 The duality of language models in the browser 10,000-watt GPU meet 40-watt lump of meat I don’t want a screenshot of your Claude conversation When moving fast, talking is the first thing to break Inverted themes with light-dark() Ozempic dreams Before I go: People like it when other people make things People are not friction Smaller and dumber Priority of idle hands Magic Words Write about the future you want I’m swearing off APIs entirely Waiting for the power to go out The best version of my site so far… Focus rings with nested contrast-color()? Interpolate contrast-color() to manipulate lightness Using your design system colors with contrast-color() Algorithmic hover states with contrast-color() Twenty Twenty-Five Vibe Check №41
Introducing Microlighter
Dave Rupert · 2026-08-20 · via daverupert.com

I made a smol client-side syntax highlighter that uses the CSS Custom Highlights API called MicroLighter. I’ll talk about why I made it in a bit but first I wanted to… ahem… highlight… some of the features.

At some point I broke syntax highlighting on my Jekyll blog. I’ve used a handful of syntax highlighters over the years (Highlight.js, PrismJS, Rouge, Shiki, etc, etc) and I’ve felt the trade-offs between different client-side and server-side implementations. Faced with picking another, I knew I wanted to explore Bramus’s technique of syntax highlighting with the CSS Custom Highlights API.

There’s some limitations with the CSS ::highlight() pseudo; no italics, no bold, no font swapping – but otherwise it’s pretty cool syntax to idiomatically express “I want to highlight this token” via CSS instead of injecting spans everywhere. Using the Highlight API means I avoid any DOM mutation and the scope of the library shrinks down to: scan code blocks using regex patterns and send CSS.highlights.set(category, textRanges) to highlight the code blocks.

I don’t need much syntax highlighting on this site. Not all posts have code and my code samples are a whole fifteen lines long at best. My struggle is that I swap languages often. I’ll do HTML, CSS, and JavaScript all in the same post. A little bash here, a little ruby there, some markdown as a treat. Using so all those languages grew the complexity beyond the limits of my regex-fu, so I decided to lean on Textmate’s established collections of patterns used by VS Code. And before I knew it, my little highlighter could do almost any language.

Knowing I use different languages often, one principle I established was that all language grammars should be auto-loaded on-demand to reduce configuration and bundle size. That way you only pay for what you use.

Inspired by PrismJS’s simplified token categories I flattened down Textmate’s granular token categories to a more human-friendly set, making it easier to style. In addition to that, one enormous nit-pick I have with codeblock styling is that light and dark themes are separate entities, so I merged them into one theme using light-dark().

The last big opinion I baked in was that I wanted the syntax highlighter to do one job: infer language and highlight code in that language. With that a guideline, I moved all extra functionality (like line-numbers, etc) over to a web component. The vanilla web component adds about ~1 KiB in size, but co-locating UI into a UI primitive like native custom elements feels right and the ShadowDOM encapsulation makes it easy to separate the code from the presentational UI.

Obviously, I’m a web component pervert but it feels like a great separation of concerns versus trying to cram everything into core library.

Try it out

To get started on your site, I’d use the self-initializing minified bundle, but I’m also shipping ESM and a web component.

npm install microlighter
<script type="module" src="path/to/microlighter/microlighter.min.js"></script>

Like I said above, not all my posts have syntax highlighting, so I even wait to import the script unless I know there’s a page with code on it.

if(document.querySelector('pre>code').length) {
	import('path/to/microlighter/microlighter.min.js');
}

You can use the ESM version if you’re going to do something fancy yourself:

import { highlightAll } from 'microlighter'

highlightAll({
	selector: 'pre.onlyTheseGetHighlights'
})

And you can also use the web component if you want those extra features I talked about:

<micro-lighter data-syntax-theme="github" line-numbers controls="copy">
  <pre><code>Code goes here</code></pre>
</micro-lighter>

Web component classes are pretty extendible too so if I don’t support something you need, you can “fork” it by extending the base class and adding your own features.

Lastly, you can use one of the pre-supplied themes or roll your own. The basic structure is:

/**
 * Setup semantic `--syntax-*` tokens 
 * @value background | foreground | comment | keyword | 
 * operator |string | constant | function | type | variable |
 * property | tag | selector | inserted | deleted
 */
[data-syntax-theme="my-theme-name"] {
  color-scheme: light dark;

  /* Code block tokens */
  --syntax-background: light-dark(#f8f8f8, #3a3a3a);
  --syntax-foreground: light-dark(#3a3a3a, #f8f8f8);
  
  /* Highlight tokens */
  --syntax-comment: light-dark(#6e7781, #8b949e);
	--syntax-function: light-dark(#8250df, #d2a8ff);
  /* ...etc... */
}

[data-syntax-theme="my-theme-name"] pre:has(code) {
	background-color:var(--syntax-background);
	color:var(--syntax-foreground)
}

::highlight(comment) { color: var(--syntax-comment) }
::highlight(function) { color: var(--syntax-function) }
/* ...etc... */

And that’s MicroLighter. If you end up using it and trying it out, let me know what you think.