搜索 K
主题
Callouts 是 Obsidian 里最常用的排版元素——一个 > [!tip] 就能把提示、警告、示例从正文里凸显出来。但把笔记发布上网时,通用 Markdown 渲染器只会把它当成普通引用块。@vaultkit/markdown-it-obsidian-callouts 在任何 markdown-it ≥ 14 环境里补齐这块拼图:对齐 Obsidian 官方规范的完整实现,折叠形态直接产出原生 <details>,零客户端 JS。
本文是「VaultKit 包指南」系列第二篇,一份面向写作者的教程:13 种标准类型、14 个别名逐一实活演示(你看到的每个 callout 都是本站构建时真实渲染的),再到折叠、嵌套、自定义类型注册与 DOM/CSS 契约。
markdown-it 生态里的 callout 插件不少,这个包的差异点在于「对齐 Obsidian,且为静态站点做减法」:
.callout[data-callout] + --callout-color 变量,你在 Obsidian 里攒的自定义颜色 snippet 心智可以直接迁移;<details> 实现,不发一行 JS;pnpm add -D @vaultkit/markdown-it-obsidian-callouts如果你用的是 @vaultkit/vitepress-theme-vault 主题,本插件开箱即带(markdown.callouts 缺省开启,样式已引入),下面的接入步骤可以整段跳过。
任意 markdown-it 环境:
import { obsidianCallouts } from '@vaultkit/markdown-it-obsidian-callouts'
import MarkdownIt from 'markdown-it'
const md = new MarkdownIt().use(obsidianCallouts)VitePress 环境要多做两件事——停用同形语法的内置 GFM alerts,并引入样式:
// .vitepress/config.ts
import { obsidianCallouts } from '@vaultkit/markdown-it-obsidian-callouts'
import { defineConfig } from 'vitepress'
export default defineConfig({
markdown: {
gfmAlerts: false, // 内置 GFM alerts 与 callout 语法同形,必须停用其一
config(md) {
md.use(obsidianCallouts)
},
},
})// .vitepress/theme/index.ts
import '@vaultkit/markdown-it-obsidian-callouts/styles/index.css'在引用块首行写 [!类型],可选跟一个自定义标题;后续行是正文,支持任意块级内容:
> [!tip] 可选的自定义标题
> 正文是普通 Markdown,列表、代码块、嵌套引用都可以。正文是普通 Markdown,列表、代码块、嵌套引用都可以。
省略标题时,缺省标题为类型名首字母大写;省略正文(仅标题行)也合法:
> [!tip] 只有标题、没有正文的 callout 同样合法每种类型有专属的 lucide 图标与色系(色板保持 Obsidian 色相,但明暗分态调至 WCAG AA 对比度)。逐一演示:
> [!note]
> note——蓝色 + 铅笔图标,最常规的补充说明。
> [!abstract]
> abstract——青色 + 清单图标,摘要与概括。
> [!info]
> info——蓝色 + 信息图标,背景信息。
> [!todo]
> todo——蓝色 + 对勾圆圈,待办容器。
> [!tip]
> tip——青色 + 火焰图标,小技巧。
> [!success]
> success——绿色 + 对勾,操作成功。
> [!question]
> question——橙色 + 问号圆圈,疑问与解答。
> [!warning]
> warning——橙色 + 警示三角,注意事项。
> [!failure]
> failure——红色 + 叉号,失败记录。
> [!danger]
> danger——红色 + 闪电,危险操作。
> [!bug]
> bug——红色 + 虫子图标,缺陷记录。
> [!example]
> example——紫色 + 列表图标,示例演示。
> [!quote]
> quote——灰色 + 引号,引用他人。note——蓝色 + 铅笔图标,最常规的补充说明。
abstract——青色 + 清单图标,摘要与概括。
info——蓝色 + 信息图标,背景信息。
todo——蓝色 + 对勾圆圈,待办容器。
tip——青色 + 火焰图标,小技巧。
success——绿色 + 对勾,操作成功。
question——橙色 + 问号圆圈,疑问与解答。
warning——橙色 + 警示三角,注意事项。
failure——红色 + 叉号,失败记录。
danger——红色 + 闪电,危险操作。
bug——红色 + 虫子图标,缺陷记录。
example——紫色 + 列表图标,示例演示。
quote——灰色 + 引号,引用他人。
Obsidian 为常用类型准备了别名,与规范类型同色同图标,只有缺省标题不同(显示别名本身的首字母大写形式)。插件以 CALLOUT_ALIASES 常量导出全集,共 14 个,逐一演示:
> [!summary]
> `summary` → abstract
> [!tldr]
> `tldr` → abstract
> [!hint]
> `hint` → tip
> [!important]
> `important` → tip
> [!check]
> `check` → success
> [!done]
> `done` → success
> [!help]
> `help` → question
> [!faq]
> `faq` → question
> [!caution]
> `caution` → warning
> [!attention]
> `attention` → warning
> [!fail]
> `fail` → failure
> [!missing]
> `missing` → failure
> [!error]
> `error` → danger
> [!cite]
> `cite` → quotesummary → abstract
tldr → abstract
hint → tip
important → tip
check → success
done → success
help → question
faq → question
caution → warning
attention → warning
fail → failure
missing → failure
error → danger
cite → quote
速查表(规范类型 → 别名 → 图标):
| 规范类型 | 别名 | lucide 图标 |
|---|---|---|
note | — | pencil |
abstract | summary tldr | clipboard-list |
info | — | info |
todo | — | circle-check |
tip | hint important | flame |
success | check done | check |
question | help faq | circle-help |
warning | caution attention | triangle-alert |
failure | fail missing | x |
danger | error | zap |
bug | — | bug |
example | — | list |
quote | cite | quote |
[!type]- 与 [!type]+ 类型标记后紧跟 - 或 +,callout 渲染为原生 <details>——- 默认收起、+ 默认展开,点标题即可切换,零 JS:
> [!faq]- 这条默认是收起的,点我展开
> 折叠形态是原生 `<details>` + `<summary>`,键盘可操作,无需 JavaScript。右侧箭头随展开态旋转 90°。
> [!faq]+ 这条默认是展开的,点我收起
> 适合「默认给读者看,但允许收起」的补充内容。折叠形态是原生 <details> + <summary>,键盘可操作,无需 JavaScript。右侧箭头随展开态旋转 90°。
适合「默认给读者看,但允许收起」的补充内容。
标题支持行内 Markdown——粗体、行内代码,甚至 wikilink:
> [!tip] 标题里可以有 **粗体**、`行内代码` 与 [[Minimal Theme|双链]]
> 标题内的行内元素继承标题色,不会被宿主主题的链接色打花。行内代码 与 双链标题内的行内元素继承标题色,不会被宿主主题的链接色打花。
类型标识大小写不敏感,[!NOTE]、[!Note]、[!note] 完全等价:
> [!NOTE] 大写 NOTE 与小写 note 等价
> 从 GitHub README 粘贴过来的大写写法无需修改。从 GitHub README 粘贴过来的大写写法无需修改。
未注册的类型不会报错,而是回退 note 样式(Obsidian 行为),缺省标题显示原类型名:
> [!spoiler]
> `spoiler` 未注册,样式回退 note 蓝,`data-callout` 属性仍保留原值 `spoiler`——想给它专属颜色补一条 CSS 即可(见下文契约一节)。spoiler 未注册,样式回退 note 蓝,data-callout 属性仍保留原值 spoiler——想给它专属颜色补一条 CSS 即可(见下文契约一节)。
callout 可以多层嵌套,插件从内向外转换,嵌套层自动收紧间距:
> [!question] 外层:callout 能嵌套吗?
> > [!success] 中层:能。
> > > [!example] 内层:多层也没问题。正文的块级能力不止于此——列表、任务清单、代码块都可以放进 callout,体例演示见 Callout 语法测试。
插件唯一的选项是 icons(类型 Record<string, string>),与内置 CALLOUT_ICONS 浅合并,两个用途:
{ tip: 'lightbulb' } 把 tip 的火焰换成灯泡;md.use(obsidianCallouts, {
icons: { idea: 'lightbulb' }, // 值是 lucide 图标名
})新类型的颜色需要自行补一条 CSS(值是 R, G, B 数值三元组,明暗两态分开给):
.callout[data-callout='idea'] {
--callout-color: 178, 106, 0;
}
.dark .callout[data-callout='idea'] {
--callout-color: 250, 173, 20;
}所有图标在插件注册时预渲染——图标名写错在构建期即抛错(@iconify-json/lucide 中不存在图标:xxx),而非渲染期静默缺图。别名与图标映射同时以 CALLOUT_ALIASES / CALLOUT_ICONS 常量导出,可编程消费。
插件产出的结构与 Obsidian 官方约定一致:
<div class="callout" data-callout="tip">
<div class="callout-title">
<span class="callout-icon"><svg …></svg></span>
<span class="callout-title-inner">标题</span>
</div>
<div class="callout-content">正文</div>
</div>关键契约点:
data-callout 保留原始类型名(含别名与未知类型),样式经属性选择器命中——这正是 Obsidian 自定义颜色 snippet 的工作方式,.callout[data-callout='x'] { --callout-color: R, G, B } 一行迁移;--callout-color 是 R, G, B 数值三元组:标题文字用 rgb(var(--callout-color)),底色用 rgba(var(--callout-color), 0.1),一个变量派生两种用途;.callout 缺省即 note 蓝,所以未知类型「自动」回退 note 样式,不需要任何 JS 判断;.dark 类(VitePress / Nuxt UI 同轨约定),色板明暗分别调色,标题对比度实测 ≥ 4.5:1(Obsidian 原版单一色板在 10% 透明底上普遍不达标);<details class="callout is-foldable">,标题换成 <summary>。GitHub 的 alerts 语法(> [!NOTE] 等五种)与 Obsidian callouts 同形。在 VitePress 宿主里必须设置 markdown.gfmAlerts: false 停用内置实现,保持全站语法单轨——否则两套规则会争抢同一段落。
停用后 GFM 五种写法照常可用,由本插件统一渲染,语义按 Obsidian 归位:NOTE / TIP / WARNING 是规范类型,IMPORTANT 是 tip 的别名、CAUTION 是 warning 的别名。从 GitHub README 迁移的文档零改动。
aria-hidden="true" 不进读屏;折叠用原生 <summary>,键盘与读屏语义免费获得;@vaultkit/markdown-it-obsidian-callouts/styles/index.css(或完全自写——DOM 契约稳定);[\w-]+,即字母、数字、下划线、连字符;检查标记行格式:[!type] 必须在引用块首行行首,类型后要么接空格 + 标题,要么直接换行。[!type] 前有多余字符不会触发转换。
忘了设 markdown.gfmAlerts: false——内置 GFM alerts 与本插件同时命中了同一段落。
icons 只注册图标与合法性,颜色走 CSS:补一条 .callout[data-callout='你的类型'] { --callout-color: R, G, B }(暗色态再补一条 .dark 前缀的)。