
5 分钟#guide #tooling
Blog 说明
这个站怎么加图、怎么发文、怎么改标签、相关阅读是怎么算的;顺手把图片和 Markdown 的能力边界一次说清。
这份说明写给两个读者:半年后忘了细节的我,和想照着改的你。
先说结论:这是一个纯静态站。写 Markdown,npm run build,上传 dist/。没有数据库,没有后台,没有运行时框架。
一、图片
放在哪里
assets/images/ 站内零散图片(头像、封面、首页大图、友链头像)
assets/gallery/full/ 相册原图
assets/gallery/preview/ 相册预览(列表用)
assets/gallery/thumbs/ 相册缩略图(网格用)
assets/ 会被整目录复制进 dist/,所以路径就是它们未来的 URL。
文章里怎么引用
写相对路径就行,不用带 images/:

构建时会做两件事:
- 补全成
images/greenhouse.webp(已经写了images/或以/、http(s)开头的原样保留); - 读出真实宽高写进
width/height,再挂上loading="lazy"—— 这是这个站几乎不抖的原因。
能读尺寸的格式:PNG、JPEG、WebP。SVG 和 GIF 读不到,会退化成没有尺寸(可能抖一下),建议别放正文。
封面
cover: greenhouse.webp
cover 会出现在首页置顶卡和文章页顶部。同样只写文件名。
相册
相册不走 Markdown,走数据:data/gallery.json。
{
"slug": "greenhouse",
"title": "温室里的两只",
"desc": "向日葵开满的那个下午。",
"alt": "两只小兽依偎在花丛中",
"date": "2026-09-18",
"width": 1600,
"height": 901,
"tags": ["插画"],
"license": "CC BY-NC-SA 4.0",
"meta": [["尺寸", "1600 × 901"], ["格式", "WebP"]]
}
三档图按 <slug>.webp 命名放在三个目录下;src / preview / thumb 不写时按约定拼。
相册页支持双击、回车、触控打开灯箱,左右键切换,打开时会预取相邻两张。
图片的缺陷,先讲清楚
| 限制 | 说明 |
|---|---|
| 文章里的图没有灯箱 | 灯箱只给相册。想放大只能浏览器缩放 |
| 不能指定显示尺寸 |  这种 Obsidian 写法不被解析,只能靠原图和 CSS |
| 不能直接粘贴 | 没有上传接口,得自己把文件放进 assets/images/ |
| 不做自动压缩 | 放多大的图就发多大的图,投放前自己压 |
没有响应式 srcset |
正文图只输出一个 src |
自定义壁纸
最底层那张背景默认是内置渐变。想换成图片,改 site.json:
"canvas": {
"wallpaper": "images/hero-1600.webp",
"veil": 0
}
- 路径相对
assets/,不用写assets/本身;构建时会按页面深度补前缀,子页面也不会断。 - 留空就用渐变壁纸。
- 设了图片会自动压一层底色(亮色白纱、暗色黑纱),避免正文直接压在照片纹理上。
- 文件找不到时构建会打印一行提示并忽略,不会产出 404。
- 壁纸层同时是玻璃窗口的折射源,换成图片后折射会跟着换。
背景里那三个飘动的光团(.bubble)是纯装饰:位置、时长在 assets/style.css 里,关掉不影响任何功能。
二、Markdown 支持到什么程度
渲染器是 markdown-it 加几个插件,再补一层 Obsidian 方言。支持:
- 基础:标题、段落、粗斜体、行内代码、围栏代码块(带语言 class)、引用、有序/无序/嵌套列表、链接、图片、分隔线
- 表格:带
:---:对齐,外面自动包一层.table-wrap(窄屏横向滚动) - 删除线
~~删~~、高亮==亮== - 任务列表
- [ ]/- [x]:真 checkbox(禁用态),勾选的自动划线 - 脚注
文字[^1]+[^1]: 内容:正文上标、文末「脚注」区、双向锚点 - callout:
> [!note] 标题,类型有 note / info / tip / warning / danger / success / example / quote / fail / bug / important,另有 abstract、summary、tldr、todo、hint、question、help、faq、caution、attention、check、done、failure、missing、error、cite 这些别名 - 内链
[[某个标题]]或[[某个标题|别名]]:如果指的是本文里的标题,会变成锚点跳转;指不到就渲染成斜体虚线标记,并在构建时提示 - 注释 ``
- 外链自动加
target="_blank" rel="noopener noreferrer"
标题的两条规矩
- 文档里最浅的那一级标题对齐到 h2,其余保持相对层级。所以整篇只用
#写也不会有两个 h1。 - id 由标题文字生成(中文也保留),重复的自动加
-1。目录、锚点、内链都靠它。
中文软换行
源码里在句子中间换行,中文之间不会多出空格;中英之间保留一个空格。
Markdown 的缺陷
| 不支持的写法 | 现在的结果 |
|---|---|
原始 HTML <kbd>、<span> |
一律转义成文本(只有代码块里有意义) |
数学公式 $E=mc^2$ |
原样显示 |
| mermaid 图 | 当普通代码块 |
Obsidian 嵌入 ![[图片.webp]] |
显示成行内代码,构建时提示改用  |
| 图片尺寸/对齐语法 | 忽略 |
定义列表、目录块 [TOC] |
不支持(目录由模板生成) |
三、新增一篇文章
- 在
content/posts/新建<slug>.md,文件名就是 URL:content/posts/hello.md→/posts/hello/。 - 写 frontmatter:
---
title: 标题
date: 2026-11-04 # 2026-11-4 也认
tags: [design, css]
summary: 一句话摘要 # 不写就取正文首段前 96 字
cover: cover.webp # 可选
draft: false # 可选,true 时不生成
---
- 正文随便写,图片放
assets/images/。 npm run build。
首页、文章列表、归档、标签页、RSS、Atom、搜索索引、相关阅读,都是从 content/posts/ 里算出来的,不用手动登记任何地方。
四、改标签
标签只写在 frontmatter 里:
tags: [design, css]
改完重新构建,三件事会自动发生:
- 标签页
/tags/重新统计数量; - 每个标签的
/tags/<slug>/重新生成,没有文章了就不生成; - 上一页/下一页的归档、搜索索引一起更新。
标签是「按名字统计」的,大小写和空格都算不同标签;中文标签可以用,URL 会做 percent 编码。
五、相关阅读怎么来的
文章页底部的「相关阅读」规则很短:
- 取共享至少一个标签的其他文章;
- 按文章顺序(日期倒序)取前 2 篇。
所以想让两篇文章互相出现,给它们同一个标签就够了。没有共享标签时,这一块整个不显示——不会硬凑。
六、构建与部署
npm install # 构建期依赖:markdown-it 与几个插件
npm run build # 产出 dist/
npm run dev # 构建 + 本地 8899 预览
dist/ 是纯静态文件,丢给 Cloudflare Workers / Pages 即可,仓库里的 wrangler.jsonc 没有任何 main,只当静态资源用。
七、已知边界
- 构建时警告不影响产物:未解析的内链、不支持的嵌入、解析失败的日期,都会打印一行提示。
- 同屏最多两扇「真折射」窗口(首页 Hero + 最近文章卡),这是性能红线。
- 纸材质自 v5 起冻结,只修可读性问题,不再加新效果。