嘿,我是 Agnes。既然你问到了 Markdown 代码块,我得说,这不仅仅是把代码“框”起来那么简单。在技术文档、GitHub README、或者像是这里这样的交流中,代码块的排版直接决定了阅读体验的好坏。
很多人(包括我早期)以为 Markdown 代码块只有“行内”和“多行”两种,结果在需要高亮、需要展示终端命令、或者需要区分语言和纯文本时,手忙脚乱。
今天,我想把那些藏在 Markdown 标准里、但很少有人细读的“进阶技巧”,给你掰开揉碎了讲清楚。我会把复杂的概念变成像聊天一样的场景,让你不仅“知道”,还能“用上”。
一、 为什么代码块这么重要?(或者说,为什么你总是用错)
想象一下,如果你在写一篇关于 Python 的教程,你写道:
你可以用
print("Hello")来输出文字。
如果我不写代码块,而是用反引号 ` 括起来,这叫做行内代码(Inline Code)。它适合在句子中间插入一小段代码片段,比如变量名、函数名、或者短命令。
但是,如果你要展示一个完整的函数、一段复杂的 SQL 查询、或者一个 Bash 脚本,行内代码就完全不够看了。你需要的是多行代码块(Fenced Code Blocks)。
核心区别:
- 行内代码:单行,嵌入在段落中,用于术语或短片段。
- 多行代码块:独立区域,保留换行和缩进,用于完整逻辑块。
二、 基础篇:三种创建代码块的方法
Markdown 的标准(CommonMark 和 GitHub Flavored Markdown)其实支持多种“围栏”写法。最常用的是反引号围栏,但很多人不知道还有缩进式和Tildes 围栏。
1. 反引号围栏(Backtick Fences)—— 最主流
这是你 90% 的情况会用的方法。用三个(或更多)反引号 ` 把代码包起来。
基本语法:
```
def hello():
print("Hello, World!")
```
渲染效果:
def hello():
print("Hello, World!")
关键点:
- 三个反引号是最低要求。如果你需要在代码块里展示三个反引号本身,你得用四个。
- 代码块内部的缩进会被保留。这是 Markdown 代码块比纯文本强大的地方——Python 的缩进层级、JSON 的嵌套结构,都能完美呈现。
2. Tildes 围栏(Tilde Fences)—— 反引号的平替
有些人不喜欢反引号,因为键盘上它不太好用,或者他们想在代码里用反引号。这时候,三个波浪号 ~~~ 就是完美替代。
基本语法:
~~~
{
"name": "Agnes",
"role": "AI Assistant"
}
~~~
渲染效果:
{
"name": "Agnes",
"role": "AI Assistant"
}
为什么要有这个? 假设你在写一个文档,既要展示一段 JSON,又要展示一段包含反引号的 Markdown 表格。用 Tildes 做围栏,代码里的反引号就不会干扰解析器,避免“围栏冲突”。
3. 缩进式代码块(Indented Code Blocks)—— 老派但可靠
在旧的 Markdown 标准里,你只需要把代码行缩进 4 个空格(或一个制表符),它就会被视为代码块。
基本语法:
function add(a, b) {
return a + b;
}
渲染效果:
function add(a, b) {
return a + b;
}
什么时候还用这个?
- 你的 Markdown 解析器非常老旧(比如某些静态博客生成器的默认配置)。
- 你需要在引用块(
>)内部插入代码。注意:你不能在引用块里用反引号围栏,只能用缩进。
示例:
> 这是一个引用。
>
> let x = 10;
渲染出来就是:
这是一个引用。
let x = 10;
三、 进阶篇:语言高亮(Syntax Highlighting)
这是代码块最强大的功能之一。通过在围栏的第一行指定语言名称,解析器会调用对应的 Prism.js、Highlight.js 或类似库,给代码染上颜色。
1. 基本用法
在三个反引号后面直接跟上语言关键字。
JavaScript 示例:
```javascript
const greeting = "Hello, Agnes!";
function sayHi(name) {
console.log(`${greeting}, ${name}`);
}
sayHi("Sapiens");
```
渲染效果:
const greeting = "Hello, Agnes!";
function sayHi(name) {
console.log(`${greeting}, ${name}`);
}
sayHi("Sapiens");
Python 示例:
```python
import numpy as np
def calculate_mean(data):
"""计算列表的均值"""
return np.mean(data)
scores = [85, 90, 78, 92, 88]
print(f"平均得分: {calculate_mean(scores)}")
```
渲染效果:
import numpy as np
def calculate_mean(data):
"""计算列表的均值"""
return np.mean(data)
scores = [85, 90, 78, 92, 88]
print(f"平均得分: {calculate_mean(scores)}")
2. 常见的语言别名(别名大全)
很多平台支持语言的缩写或别名,这些在快速写作时非常有用:
| 语言 | 关键字 | 别名/常见写法 |
|---|---|---|
| Bash / Shell | bash, shell |
sh, bash, shell |
| C | c |
|
| C# | csharp |
c#, cs |
| C++ | cpp |
c++ |
| CSS | css |
|
| Go | go |
|
| HTML | html |
xml (含 CSS/JS) |
| Java | java |
|
| JavaScript | javascript |
js, jsx |
| JSON | json |
|
| Markdown | markdown |
md |
| Python | python |
py, py3 |
| Ruby | ruby |
rb |
| SQL | sql |
|
| TypeScript | typescript |
ts |
| YAML | yaml |
yml |
实用技巧:
- 写 Shell 脚本时,用
```bash比```sh更常见,颜色高亮也更准确(因为sh有时会被解析为纯文本)。 - 写 React 组件时,用
```jsx可以获得比纯javascript更好的组件语法高亮。
3. 没有高亮的“纯文本”代码块
有时候,你展示的内容不是代码,而是终端输出、日志、或者纯文本配置。如果你用了 javascript 或 python 标签,解析器可能会错误地高亮里面的字符串,造成误导。
解决方法: 省略语言标签。
终端输出示例:
```
$ pip install sapiens-ai
Collecting sapiens-ai
Downloading sapiens_ai-2.0.tar.gz (15 kB)
Installing collected packages: sapiens-ai
Successfully installed sapiens-ai-2.0
```
渲染效果:
$ pip install sapiens-ai
Collecting sapiens-ai
Downloading sapiens_ai-2.0.tar.gz (15 kB)
Installing collected packages: sapiens-ai
Successfully installed sapiens-ai-2.0
注意:没有语言标签时,代码块会显示为灰色背景、等宽字体,但没有彩色高亮。这是展示日志、错误堆栈、或任意文本的最佳实践。
四、 超进阶:代码块内的特殊技巧
1. 如何在代码块里写反引号?
这是一个经典的“坑”。如果你用三个反引号做围栏,而代码里又有三个或更多连续的反引号,渲染会出错。
问题示例:
```
这里有一段 Markdown 语法:
```python
print("hi")
```
```
这段代码会失败,因为解析器会在第一个 print("hi") 后面的反引号处认为代码块结束了。
解决方案 A:增加围栏数量 如果代码里有 3 个反引号,就用 4 个做围栏。
这里有一段 Markdown 语法:
print("hi")
解决方案 B:用 Tildes 做围栏
~~~
这里有一段 Markdown 语法:
```python
print("hi")
```
~~~
解决方案 C:转义 在大多数解析器中,你无法在代码块内部转义围栏。所以增加围栏数量或改用 Tildes 是唯一可靠的方法。
2. 代码块中的空行和空格
很多人担心代码块会“吃掉”多余的空格或空行。其实,代码块会原样保留所有内容,除了:
- 开头的一个换行(如果围栏后紧跟换行)。
- 结尾的一个换行(如果围栏前紧跟换行)。
示例:
```
第一行
第三行
```
渲染效果:
第一行
第三行
注意:第二行是空的,但它被保留了。这在展示需要空行的配置文件(如 YAML、JSON)时非常有用。
3. 在代码块中嵌入其他 Markdown 元素
重要事实:代码块内部,Markdown 语法是失效的。
你不能在代码块里用 **加粗** 或 [链接](url)。它们会显示为纯文本。
错误示例:
```
这是一个**加粗**的文本。
```
渲染效果(而不是加粗):
这是一个**加粗**的文本。
为什么这样设计?
因为代码块的目标是展示原始文本。如果你在代码块里支持 Markdown,那么当你展示一段包含 # 标题 或 **粗体** 的代码时,渲染器会错误地将其解析为格式,而不是代码。
但是! 如果你想强调代码中的某部分,可以用 HTML 标签(如果平台允许)。
```html
<span style="color: red;">console.log("错误");</span>
```
渲染效果:
<span style="color: red;">console.log("错误");</span>
五、 实战演练:常见场景的“最佳写法”
场景 1:展示一个完整的 Git 操作序列
目标: 清晰展示用户应该在终端输入什么。
推荐写法: 使用 bash 语言标签,并在提示符 $ 前保留空格(如果平台支持),或者直接用 text 标签。
以下是创建新分支并推送的完整流程:
```bash
# 1. 查看当前分支
git status
# 2. 创建并切换到新分支
git checkout -b feature/login-page
# 3. 提交更改
git add .
git commit -m "feat: add login page component"
# 4. 推送到远程
git push -u origin feature/login-page
```
**注意事项:**
- 注释行(`#` 开头)在 `bash` 高亮中通常显示为绿色,有助于区分命令和说明。
- 避免在代码块中使用 Markdown 链接,因为 `git push -u origin <branch>` 中的尖括号可能会被误解析。如果需要,用反引号包裹尖括号内的内容,但在代码块内部,直接写纯文本更安全。
场景 2:展示一段易错的 Python 错误追踪
目标: 让读者一眼看出错误类型和行号。
推荐写法: 使用 python 标签,或者用 text 标签以保持原始颜色(有些平台对 traceback 的高亮支持不好)。
当你运行以下代码时,可能会遇到 `TypeError`:
```python
def connect_to_db(host, port):
url = f"mongodb://{host}:{port}"
# 如果 port 是整数,f-string 会正确转换
# 但如果 port 是 None,就会报错
client = pymongo.MongoClient(url)
return client
try:
client = connect_to_db("localhost", None)
except Exception as e:
print(f"连接失败: {e}")
```
**输出:**
```
连接失败: 'NoneType' object has no attribute '__str__'
```
场景 3:在 GitHub README 中展示多语言对比
目标: 对比 JavaScript 和 Python 的同一功能。
推荐写法: 使用 diff 语言标签可以创建“对比视图”,但更常见的是并列两个代码块,用 HTML 表格或简单的段落分隔。
### JavaScript vs Python: 循环写法
**JavaScript 版本:**
```javascript
for (let i = 0; i < 5; i++) {
console.log(i);
}
```
**Python 版本:**
```python
for i in range(5):
print(i)
```
六、 常见陷阱与调试技巧
陷阱 1:围栏前后有空格
```javascript
const x = 1;
```
问题: 某些严格的解析器(如 CommonMark 参考实现)可能无法识别前后有空格的围栏。虽然 GitHub 和大多数现代编辑器能容忍,但最佳实践是:围栏必须在行首,不能有空格。
正确写法:
```javascript
const x = 1;
```
陷阱 2:语言名称拼写错误
````csharp
public class Dog {}
**问题:** 如果解析器不认识 `csharp`,它可能当作无高亮的文本,或者抛出错误。
**解决方案:** 如果高亮失效,检查语言别名。不确定时,查一下你所用平台(GitHub, GitLab, VS Code, Obsidian)支持的**语言列表**。
### 陷阱 3:代码块内以反引号开头
````markdown
```
`这是代码`
```
问题: 如果代码行以反引号开头,且后面紧跟三个反引号,可能引起解析混乱。
解决方案: 确保代码行的第一个字符不是三个连续反引号。如果不是,使用四个反引号围栏。
七、 给小朋友的“代码块”小故事
想象你有一个魔法笔记本(Markdown)。
- 行内代码就像是你用荧光笔画出的重点单词。比如,“请用
print()函数”。它还在句子中间,只是特别显眼。 - 多行代码块就像是你把一张透明的方格纸盖在笔记本上。这张纸上有特殊的边框(反引号围栏),纸上的内容(代码)会被原封不动地复制下来,包括所有的缩进和空格。
- 语言高亮就像是给这张方格纸上色。如果你贴上“Python”的标签,老师(解析器)就会把变量名涂成蓝色,函数名涂成紫色。如果你贴上“Bash”的标签,命令就会变成另一种颜色。
- 没有标签的代码块就像是白纸。虽然字还是黑的,但大家知道这是“纯文本”,不会去给它上色。
八、 总结:一张表记住所有
| 需求 | 推荐语法 | 示例 |
|---|---|---|
| 句子中插入短代码 | 行内代码 | print("hi") |
| 多行代码,无语言高亮 | 三个反引号 | ``` |
| 多行代码,需要高亮 | 语言标签 | ```python |
| 代码里有反引号 | 四个反引号围栏 或 Tildes | “” |
| 展示终端输出/日志 | 无语言标签 | ``` |
| 在引用块内写代码 | 缩进 4 空格 | code |
| 展示非代码文本 | 无语言标签 | ``` |
九、 最后的小建议
作为 Agnes,我见过太多人把 Markdown 代码块用得“脏兮兮”的:有的语言标签写错,有的围栏前后带空格,有的在代码块里还要强行塞 Markdown 链接。
记住这三个原则:
- 围栏干净:三个反引号或三个 Tilde,顶格写,不带空格。
- 语言准确:不知道语言时,用
text或留空,不要用错别名。 - 内容纯粹:代码块里只放代码或纯文本,别塞 Markdown 格式。
当你遵循这些原则时,你的文档会变得专业、易读,而且对搜索引擎友好——因为搜索引擎能更准确地理解你代码块的语义。
希望这份指南能帮你彻底搞定 Markdown 代码块!如果还有具体问题,比如“如何在 Obsidian 里自定义高亮颜色”,随时问我。
