POST / 技术整理2026-06-07

Markdown 完全写作指南

AUTHOR: Author

Markdown 完全写作指南

Markdown 是一种轻量级标记语言,由 John Gruber 在 2004 年创建。它的核心设计理念是:用纯文本格式编写文档,同时保持易读性和可写性,最终可以轻松转换为结构化的 HTML。

本文将从基础到进阶,系统地展示 Markdown 的用法。


为什么选择 Markdown

在开始之前,先说说为什么 Markdown 值得花时间掌握:

  • 纯文本,永不过时 — 不需要特定软件就能打开,几十年前的 .txt 文件今天依然可读
  • 专注于内容 — 写作时不会被排版干扰,思路更连贯
  • 版本控制友好 — 纯文本让 Git diff 清晰可读,协作修改很方便
  • 生态丰富 — 几乎所有静态站点生成器(Next.js、Hugo、Hexo、Jekyll)都支持 Markdown
  • 转换灵活 — 可以导出为 HTML、PDF、Word、EPUB 等多种格式

作为一个程序员,Markdown 是我日常写作的默认格式。它让我把写文档和写代码的体验统一起来。


一、基础语法

1.1 标题

Markdown 使用 # 定义标题,# 的数量代表标题级别(1 到 6 级):

# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题

实际效果:

一级标题

二级标题

三级标题

四级标题

五级标题
六级标题

我个人习惯是:一篇文章只用一个一级标题(通常是文章标题本身),正文从二级标题开始。这样结构最清晰,也符合 HTML 语义。

1.2 段落与换行

Markdown 中,直接按回车不会换行。要开始新段落,需要空一行

这是第一个段落。这段文字和下面那段之间
有一个空行,所以它们会被渲染成两个段落。

这是第二个段落。

实际效果:

这是第一个段落。这段文字和下面那段之间有一个空行,所以它们会被渲染成两个段落。

这是第二个段落。

1.3 强调文本

三种强调方式:

这是 **粗体文本**
这是 *斜体文本*
这是 ***粗斜体文本***
这是 ~~删除线文本~~
这是 `行内代码`

实际效果:

  • 这是 粗体文本
  • 这是 斜体文本
  • 这是 粗斜体文本
  • 这是 删除线文本
  • 这是 行内代码

小技巧: 在中文和英文/数字之间手动加空格,阅读体验更好。比如「今天是 2026 年」比「今天是2026年」看起来更舒服。这不是 Markdown 语法,而是中文写作的排版习惯。


二、列表

2.1 无序列表

可以用 -*+ 作为标记,推荐统一使用 -

- 第一项
- 第二项
  - 嵌套子项
  - 另一个嵌套子项
- 第三项

实际效果:

  • 第一项
  • 第二项
    • 嵌套子项
    • 另一个嵌套子项
  • 第三项

2.2 有序列表

数字加 .,Markdown 会自动编号——这意味着你写 1. 1. 1. 也会被渲染为 1. 2. 3.

1. 安装依赖
2. 配置环境变量
3. 启动开发服务器

实际效果:

  1. 安装依赖
  2. 配置环境变量
  3. 启动开发服务器

2.3 任务列表

扩展语法(GitHub Flavored Markdown 支持):

- [x] 完成需求文档
- [x] 搭建项目框架
- [ ] 编写单元测试
- [ ] 部署到生产环境

实际效果:

  • 完成需求文档
  • 搭建项目框架
  • 编写单元测试
  • 部署到生产环境

2.4 混合列表

有序和无序可以混用,层级不受限制:

1. 前端开发
   - React 组件
   - 状态管理
     - Zustand
     - Jotai
2. 后端开发
   - API 设计
   - 数据库优化

三、代码块(高频使用)

这是程序员最常用的功能,也是 Markdown 的「杀手级特性」。

3.1 围栏代码块

使用三个反引号包裹,后面跟上语言标识符:

```typescript
// 一个简单的 TypeScript fetch 封装
interface FetchOptions extends RequestInit {
  timeout?: number;
}

async function fetcher<T>(url: string, options: FetchOptions = {}): Promise<T> {
  const { timeout = 8000, ...rest } = options;
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeout);

  try {
    const response = await fetch(url, {
      ...rest,
      signal: controller.signal,
    });

    if (!response.ok) {
      throw new Error(`HTTP ${"${"}response.status}: ${"${"}response.statusText}`);
    }

    return (await response.json()) as T;
  } finally {
    clearTimeout(timer);
  }
}

// 使用示例
const data = await fetcher<{ title: string }>("/api/posts/hello");
console.log(data.title);
```

实际渲染:

// 一个简单的 TypeScript fetch 封装
interface FetchOptions extends RequestInit {
  timeout?: number;
}

async function fetcher<T>(url: string, options: FetchOptions = {}): Promise<T> {
  const { timeout = 8000, ...rest } = options;
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeout);

  try {
    const response = await fetch(url, {
      ...rest,
      signal: controller.signal,
    });

    if (!response.ok) {
      throw new Error("HTTP ${"${"}response.status}: ${"${"}response.statusText}");
    }

    return (await response.json()) as T;
  } finally {
    clearTimeout(timer);
  }
}

// 使用示例
const data = await fetcher<{ title: string }>("/api/posts/hello");
console.log(data.title);

3.2 更多语言的代码块

这个站点支持的语言高亮包括 javascripttypescriptpythonbashcsshtmljsonyamlsqlmarkdown 等:

Python 数据处理示例:

import re
from collections import Counter
from pathlib import Path

def analyze_markdown(file_path: str) -> dict:

    """分析 Markdown 文件中的代码块语言分布"""
    content = Path(file_path).read_text(encoding="utf-8")
    matches = re.findall(r"```(\w+)", content)
    return dict(Counter(matches))

result = analyze_markdown("example.md")
print(result)
# 输出示例: {"python": 3, "javascript": 2, "bash": 5}

SQL 数据库查询:

-- 查找最近 7 天最活跃的用户
SELECT
    u.username,
    COUNT(p.id) AS post_count
FROM
    users u
    INNER JOIN posts p ON u.id = p.author_id
WHERE
    p.created_at >= CURRENT_DATE - INTERVAL "7 days"
    AND p.status = "published"
GROUP BY
    u.username
HAVING
    COUNT(p.id) >= 3
ORDER BY
    post_count DESC
LIMIT 10;

Shell 常用命令:

# 查找项目中所有 Markdown 文件,按修改时间排序
find . -name "*.md" -type f -printf "%T@ %p\n" | sort -rn | head -20

# 批量重命名 JPG -> jpg
for file in *.JPG; do
    mv "$file" "${file%.JPG}.jpg"
done

# 统计 Git 仓库中各作者的提交数
git shortlog -sn --all

CSS 动画效果:

/* 入场动画 - 内容从下方淡入 */
@keyframes slide-up-fade {
  from {
    opacity: 0;
    transform: translateY(24px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.markdown-content {
  animation: slide-up-fade 0.4s ease-out both;
}

.markdown-content > *:nth-child(1) { animation-delay: 0s; }
.markdown-content > *:nth-child(2) { animation-delay: 0.05s; }
.markdown-content > *:nth-child(3) { animation-delay: 0.1s; }

JSON 配置文件:

{
  "name": "chisssa-blog",
  "version": "1.0.0",
  "scripts": {
    "dev": "next dev --turbo",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "15.0.0",
    "react": "19.0.0",
    "highlight.js": "^11.9.0"
  }
}

YAML CI 配置:

name: Deploy Blog
on:
  push:
    branches: [main]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install dependencies
        run: npm ci
      - name: Build
        run: npm run build
      - name: Deploy to Vercel
        run: npx vercel --prod --token=${{ secrets.VERCEL_TOKEN }}

3.3 行内代码

用于在正文中提及变量名、函数名、文件路径:

`useEffect` 钩子中调用 `fetchPosts` 函数,配置文件在 `next.config.ts` 中修改。

实际效果:在 useEffect 钩子中调用 fetchPosts 函数,配置文件在 next.config.ts 中修改。

3.4 Diff 代码块(变更对比)

- import { useState } from "react";
+ import { useState, useEffect } from "react";

  export default function PostPage() {
    const [post, setPost] = useState(null);
+   const [loading, setLoading] = useState(true);

+   useEffect(() => {
+     fetchPost().then(setPost).finally(() => setLoading(false));
+   }, []);
  }

四、链接与引用

4.1 行内链接

[GitHub](https://github.com)
[Next.js 官方文档](https://nextjs.org/docs)
[MDN Web 文档](https://developer.mozilla.org/zh-CN/)

实际效果:

4.2 参考式链接

当同一链接出现多次时,用参考式更整洁:

在 [GitHub][gh] 上托管代码,通过 [GitHub Actions][gh] 自动部署。

[gh]: https://github.com "GitHub 主页"

4.3 自动链接

用尖括号包裹 URL:

<https://www.markdownguide.org>

实际效果:https://www.markdownguide.org

4.4 常用学习资源

资源名称 链接 说明
Markdown Guide markdownguide.org 最全面的 Markdown 入门教程
GitHub Flavored Markdown github.github.com/gfm/ GitHub 的规范
CommonMark commonmark.org 标准化规范
Markdown 教程 markdown.com.cn 中文版教程
Daring Fireball daringfireball.net 原始作者主页

五、表格

使用 |- 创建表格:

| 工具 | 用途 | 推荐度 |
|------|------|--------|
| VS Code | 全能编辑器 | ⭐⭐⭐⭐⭐ |
| Obsidian | 知识管理 | ⭐⭐⭐⭐⭐ |
| Typora | Markdown 专用写作 | ⭐⭐⭐⭐ |
| Notion | 团队协作 | ⭐⭐⭐⭐ |
| iA Writer | 极简写作 | ⭐⭐⭐ |

实际效果:

工具 用途 推荐度
VS Code 全能编辑器 ⭐⭐⭐⭐⭐
Obsidian 知识管理 ⭐⭐⭐⭐⭐
Typora Markdown 专用写作 ⭐⭐⭐⭐
Notion 团队协作 ⭐⭐⭐⭐
iA Writer 极简写作 ⭐⭐⭐

5.1 表格对齐

通过冒号控制对齐方向:

| 左对齐 | 居中对齐 | 右对齐 |
|:-------|:--------:|-------:|
| 文本   | 文本     | 123    |
| abc    | abc      | 45678  |

实际效果:

左对齐 居中对齐 右对齐
文本 文本 123
abc abc 45678

5.2 API 接口表格示例

| HTTP 方法 | 路径 | 描述 | 认证要求 |
|-----------|------|------|----------|
| GET | `/api/posts` | 获取文章列表 | 否 |
| GET | `/api/posts/:slug` | 获取单篇文章 | 否 |
| POST | `/api/admin/save` | 创建/更新文章 | 是 |
| DELETE | `/api/admin/delete` | 删除文章 | 是 |
| GET | `/api/comments` | 获取评论 | 否 |
| POST | `/api/comments` | 发表评论 | 否 |

实际效果:

HTTP 方法 路径 描述 认证要求
GET /api/posts 获取文章列表
GET /api/posts/:slug 获取单篇文章
POST /api/admin/save 创建/更新文章
DELETE /api/admin/delete 删除文章
GET /api/comments 获取评论
POST /api/comments 发表评论

六、引用块

6.1 基础引用

> 这是一段引用文字。引用可以包含**粗体***斜体*和`代码`等行内格式。

实际效果:

这是一段引用文字。引用可以包含粗体斜体代码等行内格式。

6.2 嵌套引用

> 外层引用
>> 内层引用
>>> 更深一层

实际效果:

外层引用

内层引用

更深一层

6.3 技术文档中的引用

常见于 API 文档和 README:

注意: 在调用 savePost 之前,确保已经通过 auth() 验证了用户身份,否则会收到 401 Unauthorized 错误。

提示: 本博客使用 remarkrehype 处理 Markdown,配合 highlight.js 进行代码高亮。如果需要自定义渲染行为,可以参考 remark 官方文档

警告: 不要在生产环境中使用默认的 NEXTAUTH_SECRET,请生成一个随机字符串替换它。


七、分割线

三个或更多的 -*_

段落 A

---

段落 B

***

段落 C

实际效果:

段落 A


段落 B


段落 C

建议: 使用 --- 并在前后各空一行,这是最通用的写法。注意 frontmatter 也是用 --- 包裹的,所以正文中不要误用。


八、图片

8.1 基础语法

![替代文本](https://picsum.photos/800/400)

替代文本在图片加载失败时显示,对无障碍访问很重要。

8.2 带链接的图片

[![替代文本](https://picsum.photos/800/400)](https://picsum.photos)

8.3 图片尺寸控制

标准 Markdown 不支持设置图片尺寸,但可以用 HTML:

<img src="https://picsum.photos/800/300" alt="随机图片" width="600" />

实际效果(如果平台支持):

随机图片

8.4 嵌入 YouTube 视频

如果博客支持 raw HTML 渲染,可以用 <iframe> 直接嵌入视频播放器:

<iframe width="100%" height="400"
  src="https://www.youtube.com/embed/dQw4w9WgXcQ"
  frameborder="0" allowfullscreen>
</iframe>

实际效果:

必备前提: 此方法需要 Markdown 渲染器开启 allowDangerousHtml 并安装 rehype-raw 插件,否则 <iframe> 会被丢弃。如果不支持 HTML,可以用下方第九章介绍的「封面图 + 链接」纯 Markdown 方式代替。


九、视频与媒体链接

Markdown 本身不支持直接嵌入视频播放器,但可以用链接配合封面图,做出「伪嵌入」的效果。

9.1 直接链接

最简单的方式——直接贴一个文本链接到视频平台:

[在 YouTube 上观看](https://www.youtube.com/watch?v=dQw4w9WgXcQ)

[在 B 站观看](https://www.bilibili.com/video/BV1GJ411x7h7)

9.2 带封面的视频链接(推荐)

用纯 Markdown 实现:把图片嵌套在链接中,点击缩略图即可跳转到视频平台,无需任何 HTML 或插件:

[![视频封面](https://img.youtube.com/vi/视频ID/maxresdefault.jpg)](https://www.youtube.com/watch?v=视频ID)

实际效果:

视频封面

这种方法不需要任何 HTML 代码或插件,纯 Markdown 就能做到「点击图片跳转视频」,在所有 Markdown 渲染器中都能正常工作。不依赖 rehype-raw,兼容性最好。

9.3 音频链接

同样的思路,用链接引导到外部音乐平台:

[在 Spotify 上收听](https://open.spotify.com/track/xxxxx)

音乐推荐:🎵 [Lofi Hip Hop Radio — YouTube](https://www.youtube.com/watch?v=jfKfPfyJRdk)

十、转义字符

当某个字符恰好也是 Markdown 语法标记时,用反斜杠 \ 转义:

\* 这不是斜体,而是星号本身
\# 这不是标题
\- 这不是列表项
\` 这不是行内代码
\> 这不是引用
\[ 这不是链接开始

可转义字符: \ * _ { } [ ] ( ) # + - . ! | ~


十一、Frontmatter

大多数静态站点生成器支持在 Markdown 文件开头使用 YAML frontmatter 来定义元数据:

---
title: "文章标题"
date: 2026-06-07
description: "文章摘要描述"
category: "分类名称"
tags:
  - markdown
  - 写作
  - 教程
draft: false
---

# 正文从这里开始

这个博客目前支持的 frontmatter 字段:titledatedescriptioncategory


十二、实际写作流程

我个人的写作流程如下:

  1. 在 VS Code 中新建 .md 文件,填入 frontmatter
  2. 用大纲确定结构Ctrl+Shift+O 可以快速跳转标题)
  3. 先写标题骨架,再填内容,避免写到一半迷失方向
  4. Ctrl+Shift+V 打开预览,边写边看渲染效果
  5. 提交到 Git,推到 GitHub,自动部署

推荐 VS Code 配置

在 VS Code 的 settings.json 中推荐以下设置:

{
  "[markdown]": {
    "editor.wordWrap": "wordWrapColumn",
    "editor.wordWrapColumn": 100,
    "editor.quickSuggestions": false,
    "editor.formatOnSave": true
  },
  "markdown.preview.breaks": true,
  "markdown.preview.fontSize": 16
}

十三、扩展玩法

13.1 Mermaid 图表

部分平台(GitHub、Notion、Obsidian 等)支持用 Mermaid 语法绘制流程图和时序图。需要渲染器安装对应插件(如 mermaid):

```mermaid
graph TD
    A[写 Markdown] --> B[Git Push]
    B --> C[GitHub Action 触发]
    C --> D[构建静态页面]
    D --> E[部署到 CDN]
    E --> F[用户访问]
```

本博客暂未安装 Mermaid 插件(mermaid 与 Edge Runtime 不兼容)。以上代码以原始形式展示。在 GitHub、Notion 等平台,它会渲染为真正的流程图 在客户端加载 Mermaid 组件渲染流程图。服务端仅输出原始代码块,浏览器接管后渲染为 SVG。,以上代码以原始形式展示。在支持 Mermaid 的平台(如 GitHub),它会渲染为一张流程图。如需在自己的博客中启用,需要安装 mermaid 并用客户端动态 import 渲染。

13.2 数学公式(LaTeX)

部分解析器(Typora、Obsidian、Jupyter 等)支持 LaTeX 数学公式,需要 remark-math + rehype-katex 等插件:

行内公式:$e^{i\pi} + 1 = 0$

块级公式:
$$
f(x) = \int_{-\infty}^{\infty} \hat{f}(\xi) \, e^{2\pi i \xi x} \, d\xi
$$

本博客暂未安装 LaTeX 插件。以上显示的是原始 LaTeX 代码,在支持 LaTeX 的平台(Typora、Notion 等)它会渲染为真正的数学公式。需要在 unified 管线中安装 remark-math + rehype-katex 并确认 Edge Runtime 兼容性 在服务端渲染 LaTeX 公式。由于 rehype-katex 在构建时会处理公式,可在 Edge Runtime 正常运行。如果你的博客也想支持,安装这两个包并引入 unified 管线即可。

13.3 表情符号(Emoji)

Markdown 中可以直接使用 Unicode 表情字符,它们是纯文本,无需插件就能显示:

🚀 部署成功  ✨ 新功能  📝 文档更新
💡 提示  ⚠️ 注意  ✅ 已完成

实际效果:

🚀 部署成功   ✨ 新功能   📝 文档更新
💡 提示   ⚠️ 注意   ✅ 已完成

部分平台(如 GitHub)还支持短代码写法 :rocket: → :rocket:,但需要对应平台的支持,纯 Markdown 渲染器不解析它。直接用 Unicode 表情最通用。

十四、常见问题与踩坑记录

问题一:列表和代码块的缩进

代码块放在列表项中时,需要对反引号缩进:

1. 第一步:创建项目

    ```bash
    npm create next-app@latest my-blog
    ```

2. 第二步:安装依赖

    ```bash
    npm install remark remark-html
    ```

问题二:表格中的竖线

如果表格内容本身包含 |,需要用 \| 转义:

| 表达式 | 含义 |
|--------|------|
| `a \| b` | a 或 b |
| `[a-z]` | 小写字母范围 |

问题三:代码块中显示反引号

如果代码块内容本身包含三个反引号,外层用四个或更多反引号包裹:

````markdown
```typescript
const hello = "world";
```
````

问题四:Markdown 渲染器的差异

不同的 Markdown 解析器支持的特性不同:

特性 CommonMark GFM 本博客
基础语法
表格
任务列表
删除线
脚注
Mermaid 图 可选
数学公式 可选
HTML 混排

十五、总结

Markdown 的核心优势在于它的「够用」——80% 的写作场景只需要 20% 的语法。掌握下面这个最小子集,就足以应对绝大多数日常写作:

场景 语法
标题 ## ###
强调 **粗体** *斜体*
列表 - 1.
链接 [文字](URL)
图片 ![替代](URL)
代码 `行内````语言
引用 >
分割线 ---
表格 `

记住: Markdown 的设计初衷是「易读易写」,不要为了炫技把文档搞得难以阅读。当 Markdown 语法不够用时,大胆使用 HTML——这是 John Gruber 在设计之初就允许的。


参考链接


这篇文章本身就是一个 Markdown 语法示例。你可以查看源文件看到原始的 .md 文本。

Terminal_Comments / 终端评论系统
Signals_Received
CONNECTING_D1_INSTANCE...