Markdown 轉 HTML

貼上 Markdown 即時得到符合標準的 HTML,可切換自動連結、智慧標點、硬換行與原始 HTML 透傳。

輸入 Markdown,輸出符合標準的 HTML。 輸入即轉換。四個開關會改變解析器行為,下方預覽區同時呈現渲染效果,方便你一次核對原始碼與結果。

解析選項

預覽

Markdown、CommonMark 與各種方言

為什麼兩個解析器會對同一份文件產生分歧

Markdown 於 2004 年釋出,形態是一個 Perl 指令碼加一頁說明文字,沒有形式化語法。這種隨意性既是它得以流行的原因,也是同一份文件在不同工具裡渲染結果不同的原因。原始實現留下了數十處未定義行為:縮排三個空格的列表標記該怎麼處理、詞內巢狀的強調如何解析、標題前是否必須有空行。每個實現者都靠猜測填補這些空白,而且猜得各不相同。

CommonMark 就是為彌合這個鴻溝而生的。它是一份精確的規範,配有數百個一致性測試,覆蓋的正是原始版本留下的模糊場景。本轉換器使用 markdown-it,它完整通過 CommonMark 測試套件,因此輸出與 GitHub、Reddit、Discourse 以及大多數現代工具一致。在這裡能正確渲染的文件,在那些平臺上也會一樣。

GitHub Flavored Markdown 是在其之上疊加的超集:表格、刪除線、任務列表和 URL 自動連結。本工具支援表格和任務列表,示例文件裡兩者都有。這個區分在你為不可控的目標平臺寫作時很重要——表格並不屬於 CommonMark 本體,嚴格的解析器會把它原樣當作普通文本輸出。

四個開關到底改變了什麼

自動連結會把裸 URL 變成超連結。寫變更日誌和筆記時很方便,但它偏離了 CommonMark——後者要求裸連結必須用尖括號包裹。如果輸出需要在嚴格解析器之間移植,請關掉它。

智慧標點會把直引號改寫成彎引號,把 -- 轉成短破折號。這對散文是對的,但對程式碼塊之外出現的程式碼片段就是錯的,它會毫不客氣地把命令列引數改壞。行內程式碼和圍欄程式碼塊始終不受影響。

硬換行改變單個換行的含義。預設情況下 Markdown 會把連續行合併成一個段落,這符合大多數文件的預期。但聊天式輸入——使用者按回車就是想換行——必須開啟這個開關,否則排版會全部塌掉。

原始 HTML 透傳是唯一有安全後果的一項。關閉時,原始碼裡的 <img onerror=...> 會被轉義成文本顯示;開啟時,它會作為可執行標記輸出。任何使用者提交的內容都應保持關閉。

消毒是另一件事

Markdown 流水線最常見的誤解,是以為轉換器會保護你。它不會,也不該負責這件事。即便關閉了原始 HTML,連結目標仍然由攻擊者控制,[點我](javascript:alert(1)) 會生成一個瀏覽器可能執行的超連結。僅憑 Markdown 語法本身就足以構造出可用的攻擊。

正確的做法是:先轉換,再消毒,最後插入。用 DOMPurify 之類的專用消毒庫配合標籤與屬性白名單處理 HTML,然後才放進頁面。如果內容會展示給作者以外的人,這一步必須在服務端做——客戶端消毒可以被任何能直接呼叫你 API 的人繞過。本工具是在你自己的瀏覽器裡用你自己的輸入生成預覽,與釋出他人 Markdown 屬於完全不同的威脅模型。

開源說明:渲染由 markdown-it 提供,遵循 MIT 許可證。

常見問題

這裡遵循的是哪個 Markdown 方言?
CommonMark,外加 markdown-it 預設啟用的 GitHub 擴充套件,如表格和任務列表。它完整通過 CommonMark 一致性測試,因此輸出與 GitHub、Discourse 及多數現代渲染器一致。
生成的 HTML 可以直接釋出嗎?
不可以。插入頁面前務必先用 DOMPurify 之類的消毒庫處理,尤其是非你本人撰寫的內容。即使關閉了原始 HTML,連結目標仍受攻擊者控制,javascript: 協議的 URL 可能溜過去。
為什麼我的單行換行消失了?
標準 Markdown 會把連續行合併為一個段落,硬換行需要行尾兩個空格或一個空行。如果你的源文是聊天式文本、每次回車都應換行,請開啟「單個換行轉為 <br>」。
可以直接在 Markdown 裡貼上 HTML 嗎?
可以,前提是開啟「允許原始 HTML」。否則標籤會被轉義並按字面文本顯示,這是更安全的預設值。Markdown 中混寫原始 HTML 是合法的,但塊級標籤前後需要空行才能按預期解析。
我的內容會被上傳嗎?
不會。markdown-it 完全在你的瀏覽器中執行,頁面不會為你的文本發起任何網路請求。載入頁面後斷網也能繼續轉換。
為什麼智慧標點把我的程式碼弄壞了?
它會在正文範圍內改寫引號和連字元,所以寫在程式碼片段之外的 --dry-run 會變成短破折號。請用反引號包住程式碼片段,解析器絕不會在行內程式碼或圍欄程式碼塊內做標點替換。