Markdown写作心得

这一年里逐渐养成了用 Markdown 做一些简单笔记和课程作业的习惯,来来回回踩了不少坑。下面分享一些自己觉得不错的使用 Markdown 的工具和习惯。

工具

工欲善其事,必先利其器。这里我自己使用的本地编辑器是 VSCode,经常更新且集成 git 可以直接和 GitHub 上的仓库同步,同时有非常丰富的插件供选择。

VSCode

如果写作环境频繁迁移,可以使用一些在线编辑器。目前 VSCode 已经推出了网页版,但是还没有做到即开即用,我再推荐一个马克飞象。功能同样丰富,并且可以直接打印出非常精美的 pdf 格式(我比较喜欢在样式设置中把字体调整成华文中宋)。缺点是不支持 mermaid,画图的语法需要额外调整。

马克飞象

下面再推荐一些 VSCode 的插件:

Markdown Preview Enhanced

可以说是 Markdown All in One,集成了相当丰富的功能:$\KaTeX$ 数学公式渲染、mermaid 流程图、Markdown 转换成 ppt(html 格式的,可以在浏览器中切页)、Markdown 直接导出 html/pdf 等等。不足之处是 Markdown 导出 pdf 时候代码块不会自动折行而直接溢出,并且提供的几个渲染风格都太丑了(怀疑好几次实验报告因为这个拿了低分)。以下是我使用的配置:

{
  "markdown-preview-enhanced.mermaidTheme": "default",
  "markdown-preview-enhanced.previewTheme": "vue.css",
  "markdown-preview-enhanced.revealjsTheme": "serif.css"
}

markdownlint

markdownlint 是 vscode 上一款非常好用的格式检查扩展工具,它规定了许多规则并实时对文档进行检查,防止一些语法错误,同时维持文档风格的统一,使用此工具有助于形成一个良好的写作习惯和规范。但因其规则较多,写文档时很容易就出错(或不符合规则),所以需要对工具的规则有一个详细的了解,另外,有时工作要求的文档风格与 markdownlint 工具规定的规则并不相同,比如标题、列表的创建格式,缩进的空格数等等,这时就需要对规则进行一定的设置。以下是我使用的配置,含义见注释:

{
  "markdownlint.config": {
    "MD010": {
      //不能使用tab键缩进,要使用空格
      "code_blocks": false //代码块中可使用
    },
    "MD024": {
      //文档不能有内容重复的标题
      "siblings_only": true //不同标题下的子标题内容可以重复
    }
  }
}

Prettier - Code formatter

安装之后可以 Shift + Alt + F 一键格式化 Markdown 代码,非常舒服。

写作习惯

通常,大部分的写作习惯直接遵循 markdownlint 的要求和 Prettier 的格式化,就可以写出一份可读性较高的 Markdown 文档。不过,我还想分享一些插件没有提供的自己的习惯。日积月累,不定期更新~

中文文案排版指北

推荐阅读sparanoid/chinese-copywriting-guidelines

不应被排版的内容使用代码块包裹

最基本的是代码块,但是还有一些内容也有可能会被直接复制到代码编辑器中,比如:

  • 文件名
  • 屏幕 log

如果不使用代码块包裹的话,某些排版工具可能会对其造成破坏:轻则破坏缩进,重则替换字符编码(比如半角字符转全角字符)。因此,我们应该使用代码块将其包裹起来。

文章结构

和别的同学合作过一些课程笔记(如并行与分布式计算复习笔记),我发现大部分人在整理文章结构的方法上都有不同的套路。下面举几个例子:

多层列表

大概是写成这样,这样写的特点是排版起来通常比较紧凑,适合知识容量较大的内容,比如开卷笔记。

- ...
  1. ...
     - ...
     - ...
  2. ...
- ..

但是缺点也很明显,多层缩进之后每行的缩进很长,这时候插入一些比如代码块之类的多行内容就很难受。

多层引用

不知道是怎样的脑回路才能想出这样的方法…

...

> ...
>
> > ...
> >
> > > ...

...

总之这种方法是我个人绝对不推荐的,滥用了引用的含义并且渲染出来相当难看。

多级目录

这是我非常推荐的方法,使用多级目录来划分文章的结构。

# title1

...

## title2.1

...

### title3.1

...

## title2.2

...

它的好处是,目前常见的 markdown 渲染引擎都内置了基于标题的文章结构分析工具,还可以直接生成文章的目录树(比如我博客的目录)。

[toc]

缺点也有:

  • 由于 # 直接对应 html 中的 <h1></h1> 标签,且 html 通常只支持到 <h6></h6> 标签,因此目录的层级不能过多。
  • 很多内容都是一句话的事,很难再起一个标题,而直接使用标题而没有正文不大合适。
  • 由于没有缩进,在写作的时候不太方便区分当前的层级。

对于最后一点,我所使用的编辑器可以根据当前的内容生成大纲和指示器(见下图)。而对于前两者,我的建议是和多层列表混用,这样写出来的内容就比较有条理了。

图片插入

这是大部分人 markdown 写作的时候都会遇到的问题,由于 markdown 是一个纯文本语言,在插入图片的时候比较麻烦。这里我结合自建的博客进行说明。

本地保存

第一种方案是保存在本地目录下。比如之前我的博客是把所有图片保存在 /assets/image/ 目录下的,然而这样做的话在文章迁移时(如果)目录也要一起移动,并且文章多了之后图片也非常不好管理。并且,访问博客的时候是直接对博客的服务器发起请求,在直接访问服务器的情况下可能会拖慢访问速度。

使用图床

第二种方法是使用图床。常见的免费图床有微博(不错,微博也是可以做图床的)、SM.MS、七牛等,不过这样的坏处是又要记一个账号了,并且把图片托付给第三方平台,假如平台倒闭或者限流之后想做资源迁移的话,之前的问题仍然没有解决。

关于使用图床,我这里给出一种新的方法:使用 GitHub Repo + CDN(如 jsDelivr)。由于 GitHub 现在已经解除个人账户仓库大小的限制(在被微软收购之后财大气粗),可以直接将图片上传到 GitHub 仓库。由于 GitHub 直接访问非常缓慢,为了不影响博客的访问体验需要使用一些常见的 CDN 进行转发。

这里以jsdelivr为例:

https://cdn.jsdelivr.net/gh/user/repo@version/file

默认或者 @latest 标签很多时候都拉不到最新的文件,建议链接上一定要加上具体的 @version ,可以是具体的 commit 号,也可以是某个 tag。

最后给一个示例:wu-kan/MizunoAi

使用 Base64 编码后直接插入正文

某次用 jupyter notebook 炼完丹后写报告,发现 jupyter notebook 生成网页中的图片链接非常奇怪,没有直接指向某个本地文件而是以 data 开头。于是发现了用 Base64 编码将图片直接插入链接文本中的方法,从而解决了图片迁移的问题。

将图片文件转成 Base64 格式有很多方法,这里随便给出一个:https://base64.us/

但是,使用这种方法的时候需要非常注意。这相当于直接将图片插入了正文,并且 Base64 编码也会使图片大小膨胀。这样做不能让同一张图片被多次链接,并且在网页加载的时候,如果图片非常大的话会阻塞后续内容的传输(正常的图片加载是异步的)。

此外本地编辑的时候正文中也会出现非常长的文字编码链接,某种意义上还是挺影响使用的。关于这一点我曾经给 vscode 提过 issue,希望能增加一个自动折叠过长链接的选项,不过就 @vscodebot 的回复来看似乎是凉了,需要用插件来实现。有空的时候看看能不能整一个…?目前的替代解决方案是使用变量,可以参考本文的方式,点 raw 就能看到源码。

最终的结论是,图片小且数量比较多的一些图片建议压缩之后再使用 Base64 插入正文,而图片大且多次访问的时候使用图床。

最后推荐谷歌开源的在线图片压缩工具squoosh,我通常使用 Browser WebP 格式,得到的图片压缩效果比较好,所需要的配置也很少。