hexo 学习 0031:hexo 语法高亮

在技术博客中,代码块是展示核心内容的灵魂。如果代码没有颜色区分,阅读起来就像在看一堆枯燥的字符堆砌。Hexo 内置了对两大主流语法高亮库——Highlight.jsPrismJS 的支持。

你可以把语法高亮想象成给代码穿上“制服”。Highlight.js 和 PrismJS 就是两家不同的制服制造商,一家擅长在服务器端就把衣服做好(服务端高亮),另一家则提供了丰富的配件让浏览器自己去搭配(浏览器端高亮)。Hexo 允许你自由选择其中一家,甚至决定是在生成网站时穿好衣服,还是让读者打开网页时再穿。

本篇教程将详细讲解如何在 Hexo 中配置和使用这两套系统。

一、如何在文章中插入代码块

在开始配置之前,你需要知道如何在文章中写出代码块。Hexo 兼容三种写法,无论你的文章是用 Markdown、EJS 还是其他格式编写,这三种方式都通用。

1. 标签插件写法 (Tag Plugins)

这是 Hexo 原生的标签语法,功能最强大,支持标题、链接等额外选项。

完整语法:

1
2
3
{% codeblock [title] [lang:language] [url] [link text] [additional options] %}
code snippet
{% endcodeblock %}

或者使用简写 code

1
2
3
{% code [title] [lang:language] [url] [link text] [additional options] %}
code snippet
{% endcode %}

参数说明:

  • title:代码块上方的标题。
  • lang:language:指定编程语言(如 js, python, yaml),用于高亮。
  • url:代码来源的链接。
  • link text:链接显示的文字。
  • additional options:其他选项,如 mark(高亮特定行)、first_line(起始行号)等。

示例:

1
2
3
{% codeblock Hello World lang:js https://example.com 'View Source' %}
console.log('Hello Hexo');
{% endcodeblock %}

2. 反引号代码块 (Fenced Code Block)

这是标准的 Markdown 语法,Hexo 对其进行了扩展,使其支持上述标签插件的大部分功能。

语法:

1
2
3
```[language] [title] [url] [link text] [additional options]
code snippet
```

示例:

1
2
3
4
5
```python 计算斐波那契数列
def fib(n):
if n <= 1: return n
return fib(n-1) + fib(n-2)
```
计算斐波那契数列
1
2
3
def fib(n):
if n <= 1: return n
return fib(n-1) + fib(n-2)

概念辨析:三种写法的区别

  • 标签插件 ({% codeblock %}):功能最全,兼容性最好,但语法稍显繁琐,容易在 Markdown 编辑器中破坏预览。
  • 反引号扩展 (```):书写最自然,符合 Markdown 习惯,推荐使用。Hexo 会自动识别其中的扩展参数。
  • 标准 Markdown:如果你只写 ```` ```js ` 而不加其他参数,它就是标准的 Markdown 代码块,Hexo 也会正常处理高亮。

二、核心配置:选择高亮引擎

Hexo 的高亮配置位于站点根目录的 _config.yml 文件中。根据 Hexo 版本的不同(以 v7.0.0 为界),配置方式略有差异。

1. Hexo v7.0.0 及以上版本

新版本引入了 syntax_highlighter 字段来统一切换引擎。

启用 Highlight.js (默认):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# _config.yml
syntax_highlighter: highlight.js
highlight:
auto_detect: false
line_number: true
line_threshold: 0
tab_replace: ""
exclude_languages:
- example
wrap: true
hljs: false
prismjs:
preprocess: true
line_number: true
line_threshold: 0
tab_replace: ""

启用 PrismJS:
你需要将主开关设为 prismjs,并确保护 highlight 下的配置不冲突(通常只需改主开关即可,Hexo 会自动忽略未选中的引擎配置)。

1
2
3
4
5
6
7
# _config.yml
syntax_highlighter: prismjs
# 下方 prismjs 的具体配置项可根据需要调整
prismjs:
preprocess: true
line_number: true
# ...

禁用所有内置高亮:
如果你想完全自己控制(例如使用浏览器端的第三方库),可以将开关留空。

1
2
# _config.yml
syntax_highlighter:

此时,代码块将输出最原始的 HTML 结构(<pre><code class="language">),由渲染器(如 marked.js)控制基础结构。

2. Hexo v7.0.0 以下版本

旧版本通过 enable 布尔值来独立控制两个引擎。注意:两者不能同时开启。

启用 Highlight.js:

1
2
3
4
5
6
# _config.yml
highlight:
enable: true
# ... 其他配置
prismjs:
enable: false

启用 PrismJS:

1
2
3
4
5
6
# _config.yml
highlight:
enable: false
prismjs:
enable: true
# ... 其他配置

禁用所有:

1
2
3
4
5
# _config.yml
highlight:
enable: false
prismjs:
enable: false

三、深度解析 Highlight.js 配置

Highlight.js 是 Hexo 的默认高亮引擎,它在服务器端(生成静态文件时)完成高亮处理。这意味着用户看到的 HTML 已经带有颜色样式,加载速度快,且无需浏览器执行额外 JS。

1. auto_detect (自动检测语言)

  • 功能:让 Highlight.js 自动猜测代码块的语言,即使你在文章中没有标注 lang:js
  • 适用场景:当你需要“子语言高亮”时(例如在 HTML 代码块中高亮内部的 JS 脚本),或者你懒得每次都给代码块标语言。
  • 警告:此功能非常消耗 CPU 资源,会显著增加生成网站的时间。除非必要,否则不建议开启
  • 配置示例
    1
    2
    highlight:
    auto_detect: false # 推荐保持关闭

2. line_number (显示行号)

  • 功能:在代码块左侧显示行号。
  • 原理:Highlight.js 本身不支持行号。Hexo 通过包裹一层 <figure><table> 标签来模拟行号效果。
  • 生成的 HTML 结构
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <figure class="highlight yaml">
    <table>
    <tbody>
    <tr>
    <td class="gutter"><pre><span class="line">1</span><br></pre></td>
    <td class="code"><pre><span class="line">...</span></pre></td>
    </tr>
    </tbody>
    </table>
    </figure>
  • 注意事项:由于引入了表格布局,你可能需要在主题 CSS 中针对 figure.highlight table 编写样式,以确保行号和代码对齐美观。

3. line_threshold (行号阈值)

  • 功能:只有当代码行数超过设定值时,才显示行号。
  • 用途:避免只有一两行代码时也显示行号,造成视觉浪费。
  • 配置示例
    1
    2
    3
    highlight:
    line_number: true
    line_threshold: 5 # 只有超过 5 行的代码块才显示行号

4. tab_replace (制表符替换)

  • 功能:将代码中的 Tab 字符 (\t) 替换为指定数量的空格。
  • 默认值:2 个空格。
  • 配置示例
    1
    2
    highlight:
    tab_replace: " " # 替换为 4 个空格

5. exclude_languages (排除语言)

  • 功能:指定某些语言不进行高亮处理,仅输出纯文本代码块。
  • 用途:某些语言的高亮效果不好,或者你希望某些特定格式(如日志文件)保持原样。
  • 配置示例
    1
    2
    3
    4
    highlight:
    exclude_languages:
    - example
    - log
    此时,这些语言的代码块只会生成 <pre><code class="example">...</code></pre>,内部不会有复杂的 <span> 标签。

6. wrap (包裹模式)

  • 功能:是否使用 <figure><table> 包裹代码。
  • 依赖关系line_number 功能强依赖于 wrap。如果你开启 line_number: true,Hexo 会强制开启 wrap,即使你设置 wrap: false 也会失效。
  • 如何获得原生 Highlight.js 行为
    如果你不需要行号,只想得到最纯净的 <pre><code> 结构(方便直接应用 highlight.js 的官方 CSS 主题),必须同时关闭这两个选项:
    1
    2
    3
    4
    highlight:
    line_number: false
    wrap: false
    hljs: true # 建议开启,见下文

7. hljs (类名前缀)

  • 功能:是否在生成的 HTML class 中添加 hljs- 前缀。
  • 背景:Highlight.js 的官方 CSS 主题通常要求 class 带有 hljs- 前缀(如 hljs-comment),而 Hexo 默认为了兼容性去掉了这个前缀。
  • 配置示例
    1
    2
    highlight:
    hljs: true
    效果对比
    • hljs: false (默认): <span class="comment">
    • hljs: true: <span class="hljs-comment">
  • 最佳实践:如果你打算直接使用 Highlight.js 官网下载的 CSS 主题文件,请务必设置 line_number: false, wrap: false, 以及 hljs: true

四、深度解析 PrismJS 配置

PrismJS 是另一个流行的高亮库,它以轻量级和丰富的插件生态著称。Hexo 支持将其运行在服务端(Preprocess)或浏览器端。

1. preprocess (预处理模式)

这是 PrismJS 配置中最核心的选项,决定了高亮发生的时机。

  • preprocess: true (服务端高亮 - 推荐)

    • 行为:在 hexo generate 时,Hexo 直接计算出带颜色的 HTML。
    • 优点:页面加载极快,SEO 友好,无闪烁。
    • 行号支持:当 line_number: true 时,Hexo 会自动生成所需的 HTML 结构。你只需要在主题中引入 prism-line-numbers.css 即可,不需要引入 JS 文件。
    • 限制:无法使用那些依赖浏览器端动态分析的 Prism 插件。
  • preprocess: false (浏览器端高亮)

    • 行为:Hexo 只输出带有语言标记的原始代码块,高亮由浏览器加载 PrismJS 的 JS 库后动态执行。
    • 优点:可以使用 PrismJS 的所有插件(如实时高亮特定行、工具提示等)。
    • 代价:增加了浏览器的 JS 执行负担,页面加载初期可能看到无色代码(闪烁)。
    • 行号支持:Hexo 不会生成行号所需的 HTML 结构。你必须手动在主题中同时引入 prism-line-numbers.css prism-line-numbers.js
    • 特定行高亮:如果你在代码块中使用了 mark 选项(高亮特定行),Hexo 依然会生成相应的 HTML 结构,即使在此模式下。

配置示例 (服务端模式):

1
2
3
4
5
# _config.yml
syntax_highlighter: prismjs # 或 highlight.enable: false / prismjs.enable: true
prismjs:
preprocess: true
line_number: true

此时只需在模板引入 CSS:

1
<link rel="stylesheet" href="/css/prism-line-numbers.css">

配置示例 (浏览器端模式):

1
2
3
4
# _config.yml
prismjs:
preprocess: false
line_number: true

此时需在模板引入 CSS 和 JS:

1
2
<link rel="stylesheet" href="/css/prism-line-numbers.css">
<script src="/js/prism-line-numbers.js"></script>

2. line_number & line_threshold & tab_replace

这三个参数的功能与 Highlight.js 中的完全一致:

  • line_number: 开启行号。注意:PrismJS 的行号同样依赖内部包裹结构,无法在关闭 wrap (隐式) 的情况下单独开启行号。
  • line_threshold: 行号显示的行数阈值。
  • tab_replace: Tab 转空格策略。

3. 插件兼容性特别说明

当使用 preprocess: false 时,PrismJS 的插件支持情况如下:

  • 行号 (Line Numbers):需手动引入 CSS + JS。
  • 显示语言 (Show Language):Hexo 会自动为代码块添加 data-language 属性,配合 Prism 的 show-language 插件即可显示角标。
  • 高亮特定行 (Line Highlight):Hexo 的代码块标签支持 mark 参数(如 {% codeblock mark:[1,3-5] %})。无论 preprocess 是 true 还是 false,Hexo 都会生成对应的 HTML 标记,但浏览器端模式下需确保引入了 line-highlight 插件的 JS/CSS。

五、总结与选型建议

面对两种引擎和多种配置,初学者该如何选择?

  1. 追求性能与 SEO (大多数博客)

    • 选择 Highlight.js (默认) 或 PrismJS (preprocess: true)
    • 理由:高亮工作在构建时完成,用户打开网页即看到彩色代码,速度最快,对搜索引擎最友好。
    • 配置要点:开启 line_number,根据需要调整 tab_replace。如果使用 Highlight.js 且想套用官方主题,记得设 hljs: true 并关闭 wrap
  2. 追求极致插件功能

    • 选择 PrismJS (preprocess: false)
    • 理由:如果你需要使用 Prism 特有的复杂插件(如实时编辑高亮、复杂的悬浮提示),必须让它在浏览器端运行。
    • 配置要点:记得手动在主题中引入对应的 JS 和 CSS 文件。
  3. 完全自定义

    • 禁用所有内置高亮 (syntax_highlighter: 留空)。
    • 理由:你想引入最新版的 Highlight.js CDN,或者使用完全不同的着色方案。此时 Hexo 只负责输出最纯净的 <pre><code> 结构。

无论选择哪种方式,理解 line_numberwrap 的依赖关系,以及 preprocess 对 PrismJS 行为的决定性影响,是配置成功的关键。