原理#
尝试使用 astro-typst ↗ 渲染数学公式。
笑死,完全用不了,样式也是乱的,目录也是乱的,渲染也是乱的。
于是使用 rehype-typst,并大量定制主题样式,有了现在这个勉强可以接受的渲染方案。这样今后我 Obsidian 上的数学笔记就能同步过来了。
参考了博主 huawen ↗ 的方案,在此致谢。
如果只需要渲染 Typst Math,装个rehype-typst后直接写就行了。但我遇到了三个问题:
- 明暗页面总有一个会吃掉Typst的文字
- 内联公式总是会自己换行。
- TOC识别元素时会将渲染出的svg里的标题元素渲染成目录项
经过和 AI 的对骂探讨,得出了修改方法
解决方案与修改内容#
1. 创建自定义Rehype插件:rehype-filter-svg-headings.ts
#
问题:TOC会识别Typst生成的SVG内部的h5:div
元素作为标题
解决方案:
- 创建了
src/plugins/rehype-filter-svg-headings.ts
插件 - 检测并过滤SVG内部的命名空间标题元素(
h5:div
) - 在构建时自动移除这些内部标题,防止它们出现在目录中
关键代码:
// 检测SVG内部的标题元素
const isHeading = node.tagName && (
/^h[1-6]$/.test(node.tagName) || // 标准HTML标题
node.tagName.includes('h5:') || // 命名空间标题如 h5:div
classNameStr.includes('tsel') // Typst选择元素
)
typescript2. 优化CSS样式:src/assets/styles/app.css
#
问题1:内联公式总是换行显示
解决方案:
- 为段落内的Typst SVG添加内联显示样式
- 优化垂直对齐和大小缩放
/* 行内公式样式 */
p .typst-doc,
p svg.typst-doc {
display: inline !important;
vertical-align: -0.3em !important;
margin: 0 0.1em !important;
max-height: 1.4em !important;
transform: scale(1.15) !important;
transform-origin: 0 0.5em !important;
}
css问题2:块级公式大小异常
解决方案:
- 确保块级公式不受行内样式影响
- 保持块级公式的原始大小
/* 块级公式 - 不受样式影响 */
.typst-doc {
display: block;
max-width: 100%;
height: auto;
}
css问题3:主题切换时Typst公式显示异常
解决方案:
- 添加JavaScript控制的深色模式支持
- 使用CSS滤镜实现颜色反转
/* JavaScript控制的深色模式 */
html.dark svg.typst-doc {
filter: invert(100%) sepia(0%) saturate(367%)
hue-rotate(19deg) brightness(105%) contrast(101%) !important;
}
/* 浅色模式重置滤镜 */
html:not(.dark) svg.typst-doc {
filter: none !important;
}
css3. 配置Astro插件#
在astro.config.ts
中配置了自定义插件:
// 添加自定义rehype插件
rehypePlugins: [
// ... 其他插件
rehypeFilterSvgHeadings,
]
typescript最终效果#
经过这些修改,现在Typst数学公式能够:
- ✅ 行内公式正确显示在行内,不换行
- ✅ 块级公式保持原始大小和块级显示
- ✅ TOC只显示真正的文章标题,不包含数学公式字符
- ✅ 在深色/浅色主题切换时正确显示
- ✅ 支持复杂的数学表达式和矩阵
大部分代码使用 Cline + DeepSeek V3.2 完成,感谢Vibe Coding救我等不会前端的小白于水火。
简单公式示例#
这是一个行内公式示例: 看起来不错的。
而这里就可以接下一行了
这里是再下一行
行间公式也能正常显示
矩阵与向量#
渲染一段完整的数学笔记#
证明:
(1).
(2).
(3).