全部文章

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/:

![温室里的两只](greenhouse.webp)

构建时会做两件事:

  1. 补全成 images/greenhouse.webp(已经写了 images/ 或以 /、http(s) 开头的原样保留);
  2. 读出真实宽高写进 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 不写时按约定拼。 相册页支持双击、回车、触控打开灯箱,左右键切换,打开时会预取相邻两张。

图片的缺陷,先讲清楚

限制 说明
文章里的图没有灯箱 灯箱只给相册。想放大只能浏览器缩放
不能指定显示尺寸 ![x](a.webp =300x) 这种 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"

标题的两条规矩

  1. 文档里最浅的那一级标题对齐到 h2,其余保持相对层级。所以整篇只用 # 写也不会有两个 h1。
  2. id 由标题文字生成(中文也保留),重复的自动加 -1。目录、锚点、内链都靠它。

中文软换行

源码里在句子中间换行,中文之间不会多出空格;中英之间保留一个空格。

Markdown 的缺陷

不支持的写法 现在的结果
原始 HTML <kbd>、<span> 一律转义成文本(只有代码块里有意义)
数学公式 $E=mc^2$ 原样显示
mermaid 图 当普通代码块
Obsidian 嵌入 ![[图片.webp]] 显示成行内代码,构建时提示改用 ![](images/…)
图片尺寸/对齐语法 忽略
定义列表、目录块 [TOC] 不支持(目录由模板生成)

三、新增一篇文章

  1. 在 content/posts/ 新建 <slug>.md,文件名就是 URL:content/posts/hello.md → /posts/hello/。
  2. 写 frontmatter:
---
title: 标题
date: 2026-11-04        # 2026-11-4 也认
tags: [design, css]
summary: 一句话摘要      # 不写就取正文首段前 96 字
cover: cover.webp       # 可选
draft: false            # 可选,true 时不生成
---
  1. 正文随便写,图片放 assets/images/。
  2. npm run build。

首页、文章列表、归档、标签页、RSS、Atom、搜索索引、相关阅读,都是从 content/posts/ 里算出来的,不用手动登记任何地方。

四、改标签

标签只写在 frontmatter 里:

tags: [design, css]

改完重新构建,三件事会自动发生:

  • 标签页 /tags/ 重新统计数量;
  • 每个标签的 /tags/<slug>/ 重新生成,没有文章了就不生成;
  • 上一页/下一页的归档、搜索索引一起更新。

标签是「按名字统计」的,大小写和空格都算不同标签;中文标签可以用,URL 会做 percent 编码。

五、相关阅读怎么来的

文章页底部的「相关阅读」规则很短:

  1. 取共享至少一个标签的其他文章;
  2. 按文章顺序(日期倒序)取前 2 篇。

所以想让两篇文章互相出现,给它们同一个标签就够了。没有共享标签时,这一块整个不显示——不会硬凑。

六、构建与部署

npm install      # 构建期依赖:markdown-it 与几个插件
npm run build    # 产出 dist/
npm run dev      # 构建 + 本地 8899 预览

dist/ 是纯静态文件,丢给 Cloudflare Workers / Pages 即可,仓库里的 wrangler.jsonc 没有任何 main,只当静态资源用。

七、已知边界

  • 构建时警告不影响产物:未解析的内链、不支持的嵌入、解析失败的日期,都会打印一行提示。
  • 同屏最多两扇「真折射」窗口(首页 Hero + 最近文章卡),这是性能红线。
  • 纸材质自 v5 起冻结,只修可读性问题,不再加新效果。

回到顶部