让博客的代码高亮适配主题
嗯,用户让我总结这篇文章,控制在100字以内,而且不需要特定的开头。首先,我需要通读整篇文章,抓住主要信息。 文章讲的是用org-publish生成博客,并且遇到了代码高亮颜色无法在亮暗主题间切换的问题。作者之前只能选一种主题,后来通过设置org-html-htmlize-output-type为css,生成CSS文件,结合light-dark实现颜色切换。还提到了写脚本合并不同主题的CSS。 所以,总结的时候要涵盖问题、解决方法和结果。控制在100字以内,直接描述内容。 </think> 作者在使用 org-publish 发布博客时遇到代码高亮颜色无法随亮暗主题切换的问题。通过设置 `org-html-htmlize-output-type` 为 `css` 并生成合并 CSS 文件,成功实现代码块颜色随主题切换。 2026-3-10 13:0:0 Author: taxodium.ink(查看原文) 阅读量:3 收藏

我的博客是用 org-publish 生成的,后面我给博客添加了主题切换(见 给博客添加 dark mode), 当时留下了一个问题 ⸺ org-publish 生成的代码高亮是内联在 HTML 标签里的,我没法通过 light-dark 去设置亮色/暗色主题下不同的颜色,只能选择一种代码高亮主题,要么是亮色,要么是暗色。

关于博客的构建见:

因为只能二选一,我最终选择的是暗色。这会导致在亮色主题下,出现一大块黑色的内容,看着有点突兀。但比在暗色主题下,出现一大块白色的内容更好,毕竟在暗色主题下,白色太刺眼了。

内联的颜色默认是当前 Emacs 的主题色,因为我平时的习惯是 随机切换主题,我当前用的 Emacs 主题和 org-publish 用到的主题未必是一致的,所以我每次在 org-publish 前还需要将 Emacs 主题重置一下。

重置主题相关的代码
(defun spike-leung/apply-theme-when-publish (&rest args)
  "Switch theme when do `org-publish'.ARGS will pass to `org-publish'."
  (require 'modus-themes)
  (require 'ef-themes)
  (require 'doric-themes)
  (let ((current-theme (car custom-enabled-themes)))
    (load-theme 'modus-vivendi t)
    (apply args)
    (when current-theme
      (disable-theme 'modus-vivendi)
      (enable-theme current-theme)
      (load-theme current-theme :no-confirm))))

(advice-remove 'org-publish #'spike-leung/apply-theme-when-publish)
(advice-remove 'load-theme #'spike-leung/set-olivetti-fringe-face)
(advice-add 'org-publish :around #'spike-leung/apply-theme-when-publish)
(advice-add 'load-theme :after #'spike-leung/set-olivetti-fringe-face)

最近又在折腾博客样式,就顺便去看了一下 org-publish 中代码块的高亮是如何实现的,于是看到了 org-html-htmlize-output-type 这个参数,将其设置为 css ,代码高亮就会使用添加类名的方式实现,而不是内联,这样我就可以基于类名去应用 light-dark 了。

(ノ>ω<)ノ 好耶!


具体做法:

使用 org-html-htmlize-generate-css 这个方法去生成当前 Emacs 主题的 CSS:

  • 找一个喜欢的 Emacs 亮色主题,生成一份 light.txt
  • 再找一个喜欢的暗色主题,生成一份 dark.txt

org-html-htmlize-generate-css 的描述是:

Create the CSS for all font definitions in the current Emacs session.

有的 font definitions 应该是需要启用了某个 mode 才会生成,可能需要在 Emacs 中,把那些常用的语言文件都访问一下,例如打开一下 .css.js.html 等文件,使得 font definitions 尽可能齐全。

写一个脚本,合并 light.txtdark.txt ,生成一份 CSS 文件,将两个主题的颜色合并,使用 light-dark 定义亮色/暗色主题下的颜色。

我现在用的 JS 脚本

如果你打算使用这个脚本,你可能需要调整一下代码中文件的路径。或者你可以找

import fs from "fs"
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const LightThemeFilePath = path.join(__dirname, ".", "light.txt");
const DarkThemeFilePath = path.join(__dirname, ".", "dark.txt");
const OutputFilePath = path.join(__dirname, "..", "publish/styles/fontify-code.css");

function parseCSS(content) {
  const rules = {};
  // org- 对应的是 ox-html.el 中 `org-html-htmlize-font-prefix` 的值
  const ruleRegex = /\.org-[^{]+\{[^}]+\}/g;

  (content.match(ruleRegex) || []).forEach(rule => {
    const selector = rule.match(/(\.org-[\w-]+)/)[1];
    const block = rule.match(/\{([^}]+)\}/)[1];
    const props = {}, comments = {};
    let lastComment = null;

    block.split('\n').forEach(line => {
      line = line.trim();
      if (!line) return;
      if (line.startsWith('/*') && line.endsWith('*/')) {
        lastComment = line; return;
      }
      const m = line.match(/^([a-z-]+)\s*:\s*([^;]+)/);
      if (m) {
        props[m[1]] = m[2].trim();
      }
    });
    rules[selector] = { properties: props };
  });
  return rules;
}

function generate(light, dark) {
  const selectors = Array.from(new Set([...Object.keys(light), ...Object.keys(dark)])).sort();
  return selectors.map(sel => {
    const l = light[sel] || { properties: {} };
    const d = dark[sel] || { properties: {} };
    const props = [...new Set([...Object.keys(l.properties), ...Object.keys(d.properties)])];

    let block = `${sel}{`;

    props.forEach(prop => {
      const lv = l.properties[prop] || '', dv = d.properties[prop] || '';
      const isColor = /color|background|border|outline/.test(prop);

      if (isColor && lv && dv) {
        block += `${prop}:${lv};${prop}:light-dark(${lv},${dv});`;
      } else if (lv) {
        block += `${prop}:${lv};`;
      } else if (dv) {
        block += `${prop}:${dv};`;
      }
    });

    return block + '}';
  }).join('');
}

const light = parseCSS(fs.readFileSync(LightThemeFilePath, 'utf8'));
const dark = parseCSS(fs.readFileSync(DarkThemeFilePath, 'utf8'));
fs.writeFileSync(OutputFilePath, generate(light, dark));
console.log('Generated Finished');

Source

最后在博客中引用生成好的 CSS 文件就好了。

Happy hacking - Emacs ♥ you!

如果你有什么想法,也可以在 让 org-publish 生成的代码高亮,基于亮色/暗色主题切换 参与讨论。

Webmentions (加载中...)

如果你想回应这篇文章,可以在你的文章或社交媒体帖子中链接这篇文章,然后提交你的 URL,你的回应随后会显示在此页面上。 (关于 Webmention)


    创建于: 2026-03-10 Tue 21:00

    修改于: 2026-03-10 Tue 21:32

    许可证: 署名—非商业性使用—相同方式共享 4.0

    支持我: 用你喜欢的方式


    文章来源: https://taxodium.ink/adapt-code-highlighting-to-the-blog-theme.html
    如有侵权请联系:admin#unsafe.sh