让博客的代码高亮适配主题
嗯,用户让我总结这篇文章,控制在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(查看原文) 阅读量:45 收藏

我的博客是用 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.txt 和 dark.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