本站 Markdown 正文速查:哪些语法真生效,哪些只是看着像
这篇与《front-matter 全字段速查》《site.yml 全字段速查》是一套:那两篇管头部(字段怎么填),这篇管正文(写下去会变成什么)。文里每条结论都是把语法真的过一遍构建期渲染器得到的(探针 site/.shots/probe-md-matrix.mjs,可复跑)。
一、一条链:md 是怎么变成页面的
source/posts/**/*.md 到页面之间没有魔法,只有五步:
gray-matter把文件切成 front-matter 与正文两段——头部走 schema 校验(见另两篇速查),正文进渲染器;markdown-it按固定三开关渲染:html:false·linkify:false·typographer:false;- 同一趟把标题清单抽出来(带 id 与层级),喂详情页右侧目录;
- 落盘
.content/posts.json——正文已经是 HTML 了; - 页面层
PostBody把这段 HTML 原样直出(dangerouslySetInnerHTML)。
第 5 步是关键:浏览器里不跑 markdown 解析器,渲染结果在构建期就定死了。所以语法写错不会在浏览器里"兜回来"——要么构建期报错,要么原样出文本。
二、开着的:日常够用的那一套
| 写法 | 出什么 | 备注 |
|---|---|---|
## 标题 / ### 标题 |
h2 / h3,自动带 id | 中文也行:## 二、小节 → id="二小节";id 重了自动加 -1;全部层级都进目录 |
**粗** *斜* ~~删除线~~ |
strong / em / s | 三样都开 |
| 无序 / 有序 / 嵌套列表 | ul / ol / 嵌套 | 标记是 ○ 与数字,颜色走淡墨 |
| 表格 | table | 1px 发丝线 + 6/12 内距(本文到处都是) |
> 引用 |
blockquote | 左侧 2px 强调色竖线,字色淡一档 |
行内 code |
code(浅色小片) | 与围栏无关,走另一条样式 |
| 围栏代码(三个反引号) | pre 深色块 |
语言名挂成 class="language-ts"——但本站没有高亮器,只挂名不染色 |
--- |
hr | 分割线 |
[文字](/portfolio) |
a | 站内相对地址与 http(s) 都行 |
 |
img | 块级居中 + 圆角;说明 进 alt |
<https://example.com> |
a | 尖括号自动链接有效(它不归 linkify 管) |
| 行尾两个空格 | <br> |
想硬换行就补两个空格,别指望单回车 |
代码块还有一项专属开关:front-matter 写 highlight_shrink: true,每个代码块会默认收成 20rem 高、右下角挂一枚胶囊按钮展开(按钮文字住 site.yml 的 a11y.post_code_expand / post_code_collapse)。下面就是被折叠的样子:
// highlight_shrink: true 时这里默认是折起来的
export function resolvePost(fm: FrontMatter, cfg: PostDefaults) {
return { toc: fm.toc ?? cfg.toc.enable }
}
三、关着的:写了也不按你想的来(逐条实测)
| 写法 | 实际结果 |
|---|---|
<div>…</div> 等原始 HTML |
被转义成文本(<div>)。html:false 是写死在 scripts/content/paths.ts 的安全不变量:正文是 dangerouslySetInnerHTML 直出,React 不做转义,放行 HTML 等于放行 XSS |
<iframe …> |
同样转义。要嵌播放器请走第四节的块级语法 |
裸 URL https://example.com |
不成链接,原样文本(linkify:false) |
脚注 [^1] |
⚠ 会变成一个指向乱码地址的链接——[^1]: 内容 被当成引用式链接定义,正文里的 [^1] 就指了过去,href 是整段正文的 URL 编码。这是本站最容易踩的坑,别用 |
任务列表 - [ ] 待办 |
只出文本 [ ] 待办 |
定义列表(词条 + : 解释) |
一个普通段落 |
emoji 短代码 :smile: |
原样文本 |
HTML 注释 <!-- … --> |
转义成文本(不会消失,会当着读者面显示) |
看到"被转义"别失望——真正需要第三方播放器的场景,第四节给了专门语法,而且它比放行 HTML 更安全:地址要过白名单。
四、本站特有的三件正文写法
1. 正文中间插播放器:块级 @[标签](播放器地址)
独立成行写这一行,播放器就落在正文的这个位置(不是正文前面,也不是顶部):
@[B 站 · 《重回1985》12 集全集连播](https://player.bilibili.com/player.html?bvid=BV1mfK767EqC&autoplay=0&high_quality=1)
- 方括号=标签(作 iframe 的可访问名,必填);圆括号=播放器地址;
- 三道闸与 front-matter 的
embeds完全同口径:必须https/ 粘 B 站页面地址会被教着换成播放器地址 / host 必须命中白名单——构建期报错并指出文件,坏块不会交付; - 独立成行才生效(块级规则);写在句子中间不识别,会原样留在段落里;代码围栏里当然也不生效(上面那段就是围栏里演示的);
- 渲染成与「视频」分节同一套 markup,零新增 CSS、零前端 JS,预渲染照旧带播放器;
- 想让它占顶部槽(16/9 独占版心)是另一条路:front-matter 的
embeds+embed_hero: true。
2. 【占位】 会被认出来
方括号里带「占位」的标记,本站不当作普通文字:
- 出现在图片/视频槽位(
cover/top_img/video.src/video.poster):归一成"没有这一槽",页面退化成占位样式,不留死链; - 出现在正文里:构建期包一层
<span class="ph">(虚线框小字),并计入上线检查表的「素材清零」进度。
也就是说:素材没到位时,写占位比留空更诚实——读者看到的是一处明确标记,而不是一个破图。
3. 素材路径:就近写母版,正文图片不必先被 front-matter 引用
正文里图片写交付地址 /images/<slug>/x.webp;母版放 source/images/<slug>/x.webp 就行。source/images/ 整个目录会被构建期搬进 dist/images/(与 source/video/ → /media/video/ 同规),所以不必先在头部声明一次才能用。
五、排版不用你操心
正文的观感不由你写,由 .prose 一套口径给:段距 16px、列表用 ○ 标记(标记色淡墨)、h2 22px / h3 19px、表格 1px 发丝线、图片块级居中带圆角、引用左侧 2px 强调线、代码块深底圆角、链接取文章强调色(main_color 可逐篇改)。
反过来说:别想在正文里写内联样式——原始 HTML 进不来(见第三节),而这类口径的唯一定义住 src/styles/,改样式是改那个地方,不是改某一篇的正文。
六、三个真会咬人的坑
- 标题自带编号 +
toc_number: true= 双编号。本站的目录编号是 CSS 计数器做的(h2 出「1.」、h3 出「1.1」)。你既手写## 一、…又开着toc_number,正文和目录就会各出一套数字。构建期会提醒(认得出「一、」「1.」「1.1 」这几种写法),二选一:要么手写编号 +toc_number: false(这几篇速查文都是这样),要么不写编号、交给自动编号。 - 正文里的链接不过构建期校验。front-matter 的
links、site.yml的内链都会被查(路由 / 锚点 / 落盘),但正文里的链接不查——内链打错字,构建不会拦,线上就是 404。自己核。 - 正文图片也不查存在性。只认交付地址(
/images/…);母版少了、文件名写错了,构建不报错,页面上是一个破图。发布前扫一眼正文里的
- 没有语法高亮:代码块只认语言名(挂在 class 上),不染色——本站没有引高亮器,将来接上也不用改正文;
- 没有公式与音乐播放器的真渲染:
mathjax/katex/aplayer目前只落成容器上的data-*钩子,第三方脚本未接入,写了不报错但也不会渲染; - 目录收全部标题层级(h1–h6,按层级嵌套):所以正文里别用
#一级标题——页面标题已经是 h1,正文再出一个 h1 是抢层级,也会一起进目录; - 本篇的每条"实测"结论都出自
.shots/probe-md-matrix.mjs:改渲染器(比如将来放开某个开关)之后,跑一遍就知道口径有没有漂。