这篇文章是本站的渲染能力样张。每一节都遵循同一格式:先给写法,再给效果。以后写作时忘了某个语法,回到这里翻一眼即可。
技术底座是 Astro + AstroPaper v6,Markdown 管线为 remark / rehype,代码高亮用 Shiki,数学公式用 KaTeX。除评论与访问统计外,所有渲染都在构建期完成,浏览器端不加载额外 JS。
Table of contents
Open Table of contents
数学公式
支持 LaTeX 语法,由 remark-math + rehype-katex 在构建期渲染成 HTML + CSS。这意味着公式在禁用 JavaScript 的环境下依然可见,也不会造成加载时的布局跳动。
行内公式
写法:用单个 $ 包裹。
质能方程 $E = mc^2$ 中,$c$ 为真空光速。
当 $n \to \infty$ 时,$\sum_{k=1}^{n} \frac{1}{k^2} \to \frac{\pi^2}{6}$。
效果:
质能方程 中, 为真空光速。 当 时,。
块级公式
写法:用 $$ 独占两行包裹。
$$
\int_{-\infty}^{\infty} e^{-x^2}\,\mathrm{d}x = \sqrt{\pi}
$$
效果:
矩阵与方程组
多行对齐推导
常用符号速查
| 类别 | 写法 | 效果 |
|---|---|---|
| 分式 | \frac{a}{b} | |
| 求和 | \sum_{i=1}^{n} x_i | |
| 极限 | \lim_{x \to 0} | |
| 偏导 | \frac{\partial L}{\partial \theta} | |
| 集合 | x \in \mathbb{R}^{n} | |
| 希腊字母 | \alpha \beta \gamma \Omega | |
| 大 O | O(n \log n) |
正文里出现落单的 $ 会被误判为公式起点。写价格时请转义成 \$,例如 \$100 渲染为 $100。写在行内代码里则不受影响。
代码块
Shiki 在构建期完成高亮,输出纯 HTML,不加载任何前端高亮库。明暗两套配色(min-light / night-owl)随主题自动切换。所有代码块右上角都有 Copy 按钮。
基础高亮
```python
def quicksort(arr: list[int]) -> list[int]:
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
return (quicksort([x for x in arr if x < pivot])
+ [x for x in arr if x == pivot]
+ quicksort([x for x in arr if x > pivot]))
```
效果:
def quicksort(arr: list[int]) -> list[int]:
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
return (quicksort([x for x in arr if x < pivot])
+ [x for x in arr if x == pivot]
+ quicksort([x for x in arr if x > pivot]))
文件名标签
在语言后加 file="路径",代码块左上角会出现带绿点的文件名徽标。
```ts file="src/utils/retry.ts"
export async function retry<T>(fn: () => Promise<T>, times = 3): Promise<T> {
let lastError: unknown;
for (let i = 0; i < times; i++) {
try {
return await fn();
} catch (err) {
lastError = err;
await new Promise(r => setTimeout(r, 2 ** i * 100));
}
}
throw lastError;
}
```
效果:
export async function retry<T>(fn: () => Promise<T>, times = 3): Promise<T> {
let lastError: unknown;
for (let i = 0; i < times; i++) {
try {
return await fn();
} catch (err) {
lastError = err;
await new Promise(r => setTimeout(r, 2 ** i * 100));
}
}
throw lastError;
}src/utils/retry.ts
行高亮与词高亮
[!code highlight] 高亮整行,[!code word:xxx] 高亮指定词。注释符号随语言变化(Python 用 #,Rust/JS 用 //)。
```rust
fn main() {
let config = load_config(); // [!code highlight]
let server = Server::new(config); // [!code highlight]
server.run(); // [!code word:server]
}
```
效果:
fn main() {
let config = load_config();
let server = Server::new(config);
server.run();
}
diff 增删标记
[!code ++] 标绿增行,[!code --] 标红删行。适合写重构、踩坑复盘。
```js
function sum(list) {
let total = 0;
for (let i = 0; i < list.length; i++) { // [!code --]
total += list[i]; // [!code --]
} // [!code --]
total = list.reduce((a, b) => a + b, 0);// [!code ++]
return total;
}
```
效果:
function sum(list) {
let total = 0;
for (let i = 0; i < list.length; i++) {
total += list[i];
}
total = list.reduce((a, b) => a + b, 0);
return total;
}
更多语言
Shiki 覆盖 200+ 语言,下面抽查几种常用的。
#!/usr/bin/env bash
set -euo pipefail
npm ci && npm run build
rsync -avz --delete dist/ "$REMOTE:/var/www/blog/"deploy.sh
SELECT u.name, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.created_at >= '2026-01-01'
GROUP BY u.name
HAVING COUNT(o.id) > 3
ORDER BY order_count DESC;
#include <stdio.h>
int main(void) {
for (int i = 0; i < 3; i++)
printf("%d\n", i * i);
return 0;
}
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"strictNullChecks": true,
"paths": { "@/*": ["src/*"] }
}
}tsconfig.json
行内代码用反引号:调用 git rebase -i HEAD~3 可以合并最近三个提交。
提示框(Callouts)
Obsidian 风格语法,共 27 种类型。写法是引用块首行加 [!类型],可跟自定义标题。
> [!note] 普通提示
> 正文内容支持 **加粗**、`行内代码`、[链接](https://astro.build) 等常规格式。
效果:
正文内容支持 加粗、行内代码、链接 等常规格式。
用于给出推荐做法。
用于强调不能忽略的信息。
用于提示风险与副作用。
用于标注可能造成数据损失的操作。
用于确认某个步骤已完成。
用于抛出待解决的问题。
用于给出具体例子。
用于引用他人观点。
可折叠提示框
类型后加 - 默认折叠,加 + 默认展开。适合收纳冗长的日志和报错栈。
> [!bug]- 点击展开:一段很长的报错栈
> ```text
> TypeError: Cannot read properties of undefined (reading 'map')
> at renderList (app.js:142:19)
> at Object.render (app.js:87:5)
> ```
效果:
点击展开:一段很长的报错栈
TypeError: Cannot read properties of undefined (reading 'map')
at renderList (app.js:142:19)
at Object.render (app.js:87:5)完整类型清单:note abstract summary tldr info todo tip hint important success check done question help faq warning attention caution failure missing fail danger error bug example quote cite。
文本与列表
基础格式
粗体、斜体、粗斜体、删除线、行内代码、外部链接、上标 H2O、下标 x2。
智能标点已开启:直引号会自动转成弯引号,-- 转成短破折号 — 像这样。
无序与有序列表
- 第一层
- 第二层
- 第三层
- 第二层
- 支持在列表项里写
代码和格式
- 第一步
- 第二步
- 子步骤
- 子步骤
- 第三步
任务列表
- 选定技术栈(Astro + AstroPaper)
- 部署到 GitHub Pages
- 接入评论与访问统计
- 迁移旧博客的历史文章
- 补一篇技术长文
引用
过早的优化是万恶之源。
—— Donald Knuth
嵌套引用:
外层引用
内层引用
表格
支持 GFM 表格与列对齐(:--- 左对齐,:---: 居中,---: 右对齐)。
| 方案 | 语言 | 构建速度 | 生态 | 适合场景 |
|---|---|---|---|---|
| Astro | JS/TS | 中 | 大 | 现代审美、组件化 |
| Hugo | Go | 极快 | 大 | 大量文章、零依赖 |
| Eleventy | JS | 快 | 中 | 高度自定义 |
| Zola | Rust | 极快 | 小 | 单二进制、极简 |
单元格内可以放 代码、格式和 公式。
图片
图片与文章一同保存在仓库中(public/images/ 或 src/assets/),不依赖外部图床,迁移时不会丢失。
文章内的图片自带无障碍灯箱:点击放大,按 Esc 关闭。
两种放法的区别:
| 位置 | 引用方式 | 是否被优化 | 适用 |
|---|---|---|---|
public/images/ | /images/foo.png | 否,原样拷贝 | SVG、需要固定 URL 的图 |
src/assets/ | ../../assets/foo.png | 是,自动压缩并生成响应式尺寸 | 照片、截图 |
脚注
支持 GFM 脚注,编号自动排序,正文与底部双向跳转。
写法:正文[^1],然后在任意位置写 [^1]: 注释内容。
Astro 采用群岛架构1,默认输出零 JavaScript2。
折叠区块
除 callout 外,也可直接写 HTML 的 <details>:
点击展开完整依赖清单
折叠区块内可以正常写段落、列表和代码,文字也可以选中复制。
astro— 框架本体@astrojs/mdx— MDX 支持remark-math/rehype-katex— 数学公式rehype-callouts— 提示框@shikijs/transformers— 代码块增强
其他
分隔线:
Emoji 直接写即可:🚀 📝 ✅ ⚠️ 🐛
键盘按键用 <kbd> 标签:按 Ctrl + K 打开搜索。
标题的锚点链接:鼠标悬停在任意标题上,右侧会出现 #,点击即可复制该小节链接。
站点级能力
以下不属于 Markdown 语法,但同样已经就绪:
| 能力 | 实现 | 说明 |
|---|---|---|
| 全文搜索 | Pagefind | 构建期生成索引,纯静态,无后端 |
| 暗色模式 | CSS 变量 | 跟随系统,也可手动切换 |
| RSS 订阅 | Astro 内置 | /rss.xml,<head> 含自动发现链接 |
| 评论 | Giscus | 基于 GitHub Discussions |
| 访问统计 | 不蒜子 | 页脚显示访客数与总访问量 |
| 分享图 | 动态 OG | 每篇文章自动生成社交预览图 |
| 阅读进度 | 顶部进度条 | 滚动时实时更新 |
| 站点地图 | @astrojs/sitemap | 自动生成,利于收录 |
写作模板
新建文章:在 src/content/posts/ 下建 .md 文件,头部写 frontmatter。
---
title: "文章标题"
pubDatetime: 2026-08-02T12:00:00+08:00
description: "一句话摘要,会用于 SEO 和文章列表。"
tags: ["标签一", "标签二"]
featured: false # 是否置顶到首页精选
draft: false # true 则不会发布
modDatetime: # 可选,修改时间
---
正文从这里开始。src/content/posts/my-post.md
写完 git push 即自动构建部署,约一分钟后线上生效。
建议把它一直留在博客里当参考。如果不想让它出现在首页精选,把 frontmatter 里的 featured 改成 false 即可;要完全隐藏则改 draft: true。