免费 Markdown 在线预览器

在左侧编写 Markdown,右侧即时查看渲染效果。支持标题、粗体、斜体、代码块、表格、列表等多种语法。

编辑器 (Markdown)
预览(已渲染)

Markdown 速查表

# Heading 1 · 顶级标题
## Heading 2 · 副标题
**bold** · 粗体文本
*italic* · 斜体文本
~~strike~~ · 删除线
`code` · 行内代码
[link](url) · 超链接
![alt](url) · 图片
- item · 无序列表
1. item · 有序列表
> quote · 引用块
--- · 水平分割线

关于 Markdown

Markdown 由 Daring Fireball 博客作者 John Gruber 创建,Aaron Swartz 在设计上给出了大量反馈。第一个公开版本 1.0 于 2004 年 3 月 9 日在 Gruber 的网站上发布;1.0.1 版本(也就是规范参考版本)于 2004 年 12 月 17 日发布,至今仍是 daringfireball.net/projects/markdown 链接到的版本。Markdown 同时是两件事:一种纯文本格式语法,以及把这种语法转换成 HTML 的原始 Perl 脚本。Gruber 明确的目标是源文本本身就要可读,一份在纯文本编辑器里打开的 Markdown 文档应当像是一封被认真排版过的电子邮件,而不是一锅标签汤。这条「可读性」约束是把 Markdown 与基于 XML 的格式以及 LaTeX 这类更重的标记分开的哲学分界线,也是为什么后来的每一项扩展都必须以「它对源文本破坏到什么程度」来为自己辩护。

Gruber 在 Markdown 的致谢中长篇地致意 Swartz:「Aaron Swartz 对 Markdown 格式语法的设计反馈值得获得巨大的肯定。」Swartz 此前曾写过一种相关的轻量标记叫 atx(2002),它贡献了如今熟悉的 ### 标题风格,在 parser 规范里,有时仍被称为「atx-style headings」。Swartz 的参与是他更广泛遗产的一部分:他少年时期参与共同构建了 RSS 1.0,直到 2007 年还是 Reddit 的共同所有者,并一直影响开放 Web 标准,直到他 2013 年去世。一个值得说清楚的小八卦:文件扩展名 .md 现在几乎是通用的,但 Gruber 原先的工具用的是 .text,迁移到 .md 是 Markdown 走出博客小众圈后形成的社区惯例。

Markdown 为什么赢得了 Web

一种标记语言要赢,得靠那些发布世界上大多数文字的平台采用它。在一段紧凑的五年窗口里,Markdown 被那些后来主导长篇讨论、代码协作和开发者文档的平台采用了。Stack Overflow 在 2008 年 9 月 15 日上线,使用 Markdown 作为问题、答案和评论的格式语法,使用的是 AttackLab 的 John Fraser 编写的一个叫 WMD(Wysiwym Markdown)的编辑器;Stack Overflow 团队后来把它重写为开源的 PageDown 编辑器,维护在 github.com/StackExchange/pagedown。Reddit 由 Steve Huffman 和 Alexis Ohanian 于 2005 年创建,Aaron Swartz 不久后加入,在上线后不久就把 Markdown 用于评论,把这套语法带给了一个更广泛、非开发者的受众。GitHub 在 2008 年上线,一年内就开始在 README.md 与 issue 评论里渲染 Markdown;2009 年它开始记录并发布自己的方言:GitHub Flavored Markdown。Discord 于 2015 年 5 月上线,采用了一种带 Markdown 风味的聊天语法,用来表示加粗、斜体、删除线、行内代码、代码栅栏与引用块,大多数 25 岁以下的非开发者现在把它理解为「在某个东西周围加星号」。这项技能的复利效应很大:一位写作者只要学会一次 Markdown,就能在 Jekyll/Hugo/Eleventy 写博客文章,在 MkDocs/Docusaurus/Read the Docs 写文档,在 Marp 与 Reveal.js 做演示文稿,在 Obsidian/Bear/Logseq/Notion 写笔记,在 Slack 与 Discord 聊天,以及在基本上每一个现代开源项目里写源代码文档。

CommonMark,修补「未规范化」

Gruber 2004 年的原始语法描述以「不正式」著称,一份带例子的散文文档,而不是文法。它把数十个边角情况留作未规范(「强调与单词中间的下划线如何相互作用?」;「引用块里的列表会关闭引用块吗?」;「什么算是紧凑列表 vs 松散列表?」),而 Gruber 除了他的 Perl 脚本之外从未发布过任何参考解析器,而那个脚本的行为以一种独特的方式特异,导致其他实现者要么照搬,要么覆盖。到 2010 年代初,结果就是 GitHub、Reddit、Stack Overflow、Pandoc 与 Discount C 解析器都把同一份 Markdown 源稍稍渲染得不一样,同样的输入也可能在不同平台之间出问题。

2012 年,Stack Overflow 联合创始人 Jeff Atwood(那时候已经在做 Discourse)和 Pandoc 的作者 John MacFarlane 开始着手撰写一份真正的、可测试的规范。后来加入的人有 David Greenspan(Meteor)、Vicent Marti(GitHub)、Neil Williams(Reddit)与 Benjamin Dumke-von der Ehe(Stack Exchange)。这个项目在 2014 年 9 月以「Standard Markdown」的名字公开;在几天内,Gruber 私下发邮件反对这个名字,Atwood 公开发文解释了改名,项目改名为「CommonMark」。第一个有编号的版本于 2014 年 10 月 25 日发布。当前发布的版本是 CommonMark 0.31.2,2024 年 1 月 28 日发布,曾承诺在 2019 年发布的「1.0」一直没有到来,因为少数几个病态边角情况(尤其是强调解析与 HTML 嵌入上)没有得到一致的解决方案。实践中,0.31.2 被当作生产就绪。CommonMark 规范不寻常的一点在于:它本身就是一份 CommonMark 文档,内联了 600 多个可执行测试用例;一个解析器声称「合规」要靠通过这些测试。

GitHub Flavored Markdown,在上面叠加的五个扩展

正式的 GFM 规范于 2017 年发布,最近一次版本号为 0.29-gfm,定于 2019 年 4 月 6 日,在 CommonMark 之上定义了五个扩展:表格(用竖线分隔的块,以一行用短横线和 : 表示按列对齐的分隔行);任务列表项(以 [ ] 开头表示未勾选,以 [x] 开头表示已勾选的列表项,渲染为禁用状态的 HTML 复选框(GitHub 还允许已登录用户通过点击切换它们,这是规范之上的一层 UX,并不属于规范本身);删除线(用 ~~ 包裹文本会得到 <del>)CommonMark 自身并没有规定这个);autolinks 扩展(行文中的裸 URL 与电子邮件地址会被自动加链接,而 CommonMark 只对显式的尖括号 autolink 这样做);以及禁用的原始 HTML(一项安全限制,会剥掉 <script><iframe><style><title><plaintext><textarea><xmp><noembed><noframes> 以及若干其他危险标签)。还有第六项常被归到 GFM 名下、但需要谨慎对待的特性:带语言标识的栅栏代码块(栅栏代码块本身就是 CommonMark 的一部分;开头栅栏后的语言提示也是 CommonMark;GitHub 之后基于这个提示所做的语法高亮则是 GitHub 自己的渲染行为,不是规范的一部分。GitHub 的渲染器还会跑一些额外的后处理)通过它自家的 html-pipeline gem 做 HTML 净化,展开 emoji 短代码(:smile:),以及对 @user#issue 自动加链接,这些都不在 GFM 本身之中。

主要的解析器

marked.js 由 Christopher Jeffrey 创建,原始版权日期为 2011 年,自 2018 年以来由 markedjs 这个 GitHub 组织维护。它采用单趟、词法器后接解析器的设计,优先追求原始速度;文档明确把它定位为「low-level compiler for parsing markdown without caching or blocking」。它就是这个预览工具目前用于实时渲染的解析器。Marked 体积小、速度快、可通过 token 钩子扩展,是 GitHub 上 star 最多的 Markdown 项目之一(约 36k stars)。

markdown-it 于 2014 年由 Vitaly Puzrin 与 Alex Kocharin 推出。两人此前曾为一个叫 Remarkable 的解析器贡献了几乎全部代码;领导权纠纷阻碍了进展之后,他们以同一作者团队重新组织成了 markdown-it。该项目宣称 100% 符合 CommonMark,并提供了表格与删除线的可选 GFM 开关,以及一个非常活跃的插件生态(markdown-it-footnote、markdown-it-emoji、markdown-it-attrs、markdown-it-anchor、markdown-it-task-lists 以及数百个其他插件)。它是 VS Code 内置 Markdown 预览、GitLab 的 Web UI 以及包括 Eleventy 在内的一长串静态站点生成器所使用的解析器。

remark / unified.js 不是单一的解析器,而是一个树变换框架。unified 集体大约从 2014 年开始,定义了一个叫 mdast(Markdown Abstract Syntax Tree)的抽象语法树规范;remark 把 Markdown 解析成 mdast,各种插件操作这棵树,然后 remark-rehype 把 mdast 转换成 hast(HTML AST)用于输出。这种模型比 marked 慢,但远更可组合。值得注意的使用方包括 Prettier(用 remark 来格式化 Markdown)、Gatsby、MDN、Node.js 的文档管线,以及 alex 这个包容性语言 linter。unified 集体列出了 312 个项目,旗下所有包加起来每月约 63 亿次 npm 下载。

MDX 由 John Otander 与其他与 Compositor 设计工具公司相关的人在 2017 年末首次提交,2018 年在 ZEIT Day 上公开发布,2019 年 4 月 11 日发布 1.0。MDX 把 Markdown 内容与 JSX 组件结合在一起,因此写作者可以直接在散文中放入一个 <Chart /> 或者 <Tweet id="123" />。它支撑了 Next.js 文档、Docusaurus 以及大多数基于 React 的文档站点。MDX 有自己独立于 CommonMark 的解析器;v1 基于 remark,v2+ 使用专门的 MDX 文法,以便在段落上下文中正确处理 JSX 表达式。

Pandoc,通用转换器

Pandoc 由 John MacFarlane 于 2006 年 8 月 10 日发布,他当时是加州大学伯克利分校的哲学教授。它用 Haskell 写成,设计核心是把大约 30 种输入格式(Markdown、reStructuredText、HTML、LaTeX、DocBook、Textile、MediaWiki 与 DokuWiki 标记、Org-mode、Microsoft Word .docx、OpenDocument、EPUB、JATS XML、Jupyter .ipynb 等)解析成一个共享的抽象文档模型,然后再把这个模型渲染成大约 40 种输出格式(HTML、通过 LaTeX 或 wkhtmltopdf 生成的 PDF、.docx、.odt、ePub2/3、包括 Beamer 与 reveal.js 在内的幻灯格式,以及更多)。它在学术与技术出版领域无所不在,因为它能够通过 CSL JSON / BibTeX 把引用一路带过去,并解析为各大主流引用风格的格式化参考文献。Pandoc 默认解析的 Markdown 方言(「Pandoc Markdown」)本身就是 CommonMark 的超集,带有脚注、定义列表、栅栏 div、数学公式(LaTeX 风格的 $...$$$...$$)以及表格说明的扩展。Pandoc 以 GPL v2-or-later 授权,是大多数学术院系用来把 Markdown 手稿编译成期刊就绪的 Word 文档的工具。

MultiMarkdown、Markdown Extra 与 SmartyPants

两个早于 CommonMark 的扩展方言对 GFM 与 Pandoc 都有影响。MultiMarkdown 由 Fletcher T. Penney 创建,2007 年 5 月首次发布(项目工作始于 2005-2006),动机来自学术写作,Penney 希望有一种 Markdown 能够生成一份带脚注、引用、数学公式、定义列表与 YAML 风格文档元数据的可发表手稿。MultiMarkdown 引入或推广了竖线字符表格、[^id] 脚注标记、数学符号、放在文件顶部的文档级元数据块,以及图片与表格的说明。Markdown Extra 由 Michel Fortin(PHP Markdown 作者)在 2005-2006 年创建,加入了竖线表格、用 ~~~(后来也用 ```)的栅栏代码块、脚注、定义列表、缩写,以及标题用的 {#id .class} 属性语法。它最具特色的贡献是放宽了「Markdown 嵌在 HTML 里」的规则(markdown="1" 属性允许你在 HTML 块内嵌套 Markdown。CommonMark 与 GFM 在栅栏代码与表格上的几个设计选择都可以追溯到 Markdown Extra。另外,SmartyPants)Gruber 自己 2002 年的排版伴侣,做的是排版替换:笔直的 ASCII 引号变成弯引号,双连字符与三连字符变成半角破折号与全角破折号,三个句点变成真正的省略号。Markdown 处理结构;SmartyPants 处理排版打磨;许多解析器把 SmartyPants 风格的行为打包成后处理步骤(markdown-it-smartypantsremark-smartypants),Pandoc 则把它内置在 --smart 选项后面。

常见陷阱,咬到新写作者的十件事

实时预览能让大多数解析意外立即变得显而易见,但理解它们为什么会发生,有助于写作者第一次就把源文本写对。

  1. 会破坏代码示例的智能引号转换。SmartyPants 风格的过滤器很乐意把看起来像散文中的引号都转换掉(有时甚至包括行内代码 span 或 HTML 属性值里面的)把你抛在一堆坏掉的标记里。大多数现代解析器会把代码 span 排除在排版替换之外,但很多用自定义流水线的博客平台并不这么做。
  2. 列表标记识别对空白敏感。在同一个列表里混用 -*+,把列表续段缩进得比标记要求的少,或者在列表项之间插入空行,都可能把一份紧凑列表翻成松散列表(每一项都被包在 <p> 标签里),这种差异在源文本里看不见,但在输出里非常显著。
  3. autolink 过头。GFM 风格的 autolinking 会把任何裸 URL 变成链接,这通常是你想要的,但也可能把本该位于代码 span 里的 URL 弄坏,或者弄坏带括号的 URL(尤其是维基百科的 URL)。「这条 URL 到哪里结束?」这条规则在不同解析器之间是不一样的。
  4. 代码栅栏的语言提示。开头三反引号后面的文本(```js```javascript```ts```typescript)只是提示,不是规范。不同的语法高亮器认识不同的别名;Highlight.js、Prism、Shiki 与 GitHub 渲染器各有各的语言字典。
  5. 需要转义的表格。表格单元格里的竖线字符必须转义为 \|,否则会被当成列分隔符。这会绊倒任何想在表格单元格里塞进一行代码示例的人。
  6. 硬换行。在一个段落里,单一的换行被当作空白,几行会被拼到一起;你要么在行尾放两个空格,要么用反斜杠,具体取决于解析器。CommonMark 两种都允许。一些更老的解析器需要显式的 <br>
  7. Markdown 与 HTML 混用。Markdown 的设计就是把任意 HTML 透传过去,所以在 Markdown 文件里塞一个 <div class="callout"> 没问题。但当你在 HTML 块内部放 Markdown 语法时,各解析器就开始分歧:CommonMark 把多数 HTML 块当作不透明;Markdown Extra 引入 markdown="1" 来选择启用嵌套解析。
  8. HTML 实体与字符转义。URL 里的 & 符号 & 在 Markdown 链接内不需要转义,但同样的 & 在链接之外会被透传到 HTML,严格 HTML5 合规可能要求把它写成 &amp;。多数渲染器会自动处理这个;有些不会。
  9. 标题 ID。GitHub 用一种 slugify 规则从标题文本自动生成 URL 片段 ID;许多解析器也这么做,但 slugify 算法不一样。同一个标题在不同平台得到的锚不一样,这是内容在不同系统之间迁移时,内部文档链接长期失效的一个老毛病。
  10. 行尾空白与编辑器设置。那些保存时会去除行尾空白的编辑器,会悄悄删掉 Markdown 的「两个行尾空格表示换行」语法。把 Tab 转成空格(或反过来)的编辑器,会破坏依赖缩进的代码块。

Markdown 与安全,XSS 与净化

Markdown 在一种特定意义上是危险的:每一个主流解析器都把原始 HTML 原样透传过去。这是有意的(这正是让 Markdown 在手写的提示框与嵌入上有用的原因)但这也意味着一个把解析器输出直接注入到 DOM 里的 Markdown 预览工具,默认就是一个 XSS 媒介。在 Markdown 编辑器里粘贴 <img src=x onerror="alert(1)">,然后在不做净化的情况下渲染输出,就会执行 alert。两层防御是标准做法。第一层,解析器层面的配置:marked.js、markdown-it 与 remark 都暴露了禁用原始 HTML 或在输出时转义它的选项(markdown-it 默认 html: false;remark/rehype 有 rehype-sanitize)。GFM 还另外指定了「禁用原始 HTML」扩展,用来剥掉一份硬编码的危险元素清单。第二层、也更稳健,解析后做 HTML 净化:DOMPurify,由柏林安全公司 Cure53 自 2014 年 2 月开始编写,是事实上的 JavaScript 净化器。它接受一段 HTML 字符串,把它解析成 DOM,遍历这棵树,只允许一份可配置、安全的元素与属性子集,然后把结果序列化出来。DOMPurify 移除 <script>,屏蔽行内事件处理器,剥掉 javascript: URL,并能处理一百种细微的 XSS 绕过(滥用 SVG <use>、MathML 属性多语言绕过等),这些是天真的正则净化器会漏掉的。任何接受原始 HTML 的浏览器内预览工具,推荐的流水线都是:markdownString → 解析器 → htmlString → DOMPurify.sanitize() → innerHTML。CommonMark 还明确要求解析器在 autolink 中拒绝 javascript: URI;大多数解析器把这条拒绝扩展到所有链接形式上。

Markdown vs reStructuredText vs AsciiDoc

Markdown 是占主导地位的轻量级标记语言,但不是唯一的。reStructuredText(reST)由 David Goodger 于 2001 年 6 月作为 Python Doc-SIG 的一部分首次发布,演化自一个叫 StructuredText 的早期 Zope 格式。它在 2002 年成为 Python 官方文档格式,也是 Sphinx 的输入语言,Sphinx 是几乎所有 Python 项目文档背后的文档生成器(官方 Python 语言文档、NumPy、SciPy、Django、Flask、scikit-learn、pandas、自 2016 年起的 Linux 内核文档、CMake、LLVM)。RST 的设计哲学本质上和 Markdown 相反:它在源文本里接受更多视觉噪声,以换取输出中更精确的语义。RST 通过「指令」(.. note::.. code-block:: python)与「角色」(:func::ref:)提供内置的扩展机制,让一个项目不必离开格式本身就能定义领域专用标记。AsciiDoc 由 Stuart Rackham 于 2002 年创建,是一个故意以 DocBook XML 语义为目标的 Python 工具(每一份 AsciiDoc 文档都能干净地映射到 DocBook)这使它成为那些需要出版级书籍、技术规范与手册的项目首选的标记格式。Git 项目的文档就是用 AsciiDoc 写的,O’Reilly Media 的许多书籍、Red Hat 与 Mozilla 的若干产品文档集都使用它,GitHub 与 GitLab 也原生支持把 README.adoc 作为替代格式。原始的 Python 实现已被 Asciidoctor 取代,后者是 2013 年发布的 Ruby 实现。实用建议:博客文章、README、聊天、笔记与大多数文档选 Markdown;由 Sphinx 处理的 Python 文档选 reStructuredText;需要同时以完整语义保真度渲染到 DocBook、PDF 与 EPUB 的长篇书籍或规范选 AsciiDoc。

常见问题

支持哪些 Markdown 功能?

本预览器支持标题、粗体、斜体、链接、图片、列表、引用、代码块、表格、水平分割线和删除线。覆盖 CommonMark 规范及常见扩展。

我可以导出渲染后的 HTML 吗?

您可以从预览面板复制渲染后的输出。如需获取原始 HTML,请在预览区右键,使用浏览器的"检查"或"查看源代码"功能来复制生成的标记。

我的文本会被保存吗?

不会。一切都在您的浏览器中运行,没有任何内容被存储或发送到服务器。关闭标签页后,您的文本就会消失。如需保存,请在离开前复制您的 Markdown 内容。

我的文本会被保存或发送到任何地方吗?

不会。Markdown 解析器完全通过 JavaScript 在你的浏览器里运行。什么都不会上传,不会调用任何 API,不会写任何日志。关掉标签页,文本就消失了。如果你想保留写过的内容,在离开这个页面之前请把它复制走。这个页面也可以离线使用,一旦加载过一次,service worker 缓存意味着即使没有互联网连接,解析器仍然可用。

这个预览工具会净化原始 HTML 吗?

解析器会把原始 HTML 原样透传过去,这是 CommonMark 的标准行为,对偶尔嵌入一个 <div><details> 块来说很有用。因为输入来自你自己的浏览器会话,输出也只在你自己的标签页里渲染,所以对它本来就是为之而建的「单人预览」用途来说是安全的。如果你要把输出发布到一个多用户系统上(一个 CMS、一个论坛、一个接受用户提交的文档站点),你应当始终先把渲染出的 HTML 送进 DOMPurify 这类净化器,然后再注入到公开页面上,只要写的人和读的人不是同一个人,Markdown 加原始 HTML 在任何系统里都是 XSS 媒介。

对文件大小有限制吗?

没有硬限制。在一台普通笔记本上,这个解析器处理上万行 Markdown 都没问题。每按一次键都会触发实时重新渲染,所以非常大的文档(在一个文件里塞下整本书)在更慢的设备上会开始觉得迟钝。把内容拆成章节,或者把内容粘进来渲染一次后再离线编辑,是绕开这个问题的办法。这个页面不会冻结你的浏览器,marked.js 是市面上最快的 Markdown 解析器之一。

相关工具