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

推荐订阅源

L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
博客园 - 司徒正美
罗磊的独立博客
D
Docker
Last Week in AI
Last Week in AI
爱范儿
爱范儿
M
MIT News - Artificial intelligence
V
V2EX
Google DeepMind News
Google DeepMind News
小众软件
小众软件
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Security Blog
Microsoft Security Blog
T
Tailwind CSS Blog
MyScale Blog
MyScale Blog
V
Visual Studio Blog
博客园 - 叶小钗
B
Blog RSS Feed
A
About on SuperTechFans
F
Fortinet All Blogs
T
The Blog of Author Tim Ferriss
Martin Fowler
Martin Fowler
P
Proofpoint News Feed

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.