- 新增两款自托管字族:font-huiwen(汇文明朝体,文风开源 cn-font-split
339 片切片包,用到页 +535KB、按需拉取实测 19/339 片)|font-kuaile
(站酷快乐体 +163KB)——补齐「宋明气质」与「轻松标题」两个字体缺口
- 首批 6 族全部 OFL-1.1 且允许 web 嵌入;未用字体的页面增量恒 +0.0KB
(按页子集化生效)
- 候补 13 款逐款标注「许可证 + web 嵌入」:HarmonyOS Sans/MiSans/OPPO
Sans/阿里普惠体(免费商用 + 明确允许嵌入,但 npm 无包/整包过大)、
得意黑/更纱/站酷高端黑/花园明朝(OFL 但无可用 npm 分发)、霞鹜文楷
Light(+8605KB 否决)、演示悠然小楷("个人免费"常禁 @font-face,风险)
- docs 写入「加字四步流程」(核双授权 → 装包或放 public/fonts → 加类+
白名单+面板项 → 跑体积账)
- 可视化面板 35 项(10 字族 + 25 颜色);白名单放行 10 字族类
- 资产:public/fonts/hwmc(339 woff2 13MB + fonts.css 162KB)入仓
车道:op-artalk;收编复验:构建 48 页、E2E 37/37、两款新字体 computed
与切片按需加载实测(hwmc/27、52 等 20 个请求)
验证: pnpm astro build 48 页 exit 0;E2E 37/37;playwright 新字体 computed
+ 字体请求观测
Spec: none (字体扩展,车道级交付)
Co-authored-by: GLM-5.3
16 KiB
写作指南:在文章里插入图片 / 视频 / 音频
适用:
content/posts/*.md(书评与技术轨通用)。资产目录约定 + 三种媒体的写法 + 体积纪律。
目录约定
content/posts/
├── my-post.md # 文章
└── assets/
└── my-post/ # 与文章 slug 同名:该篇私有资产
├── photo.jpg
├── clip.mp4
└── voice.mp3
相对引用一律 ./assets/{slug}/文件名,构建时 Astro 图片服务自动出多尺寸 webp。
图片
标准 markdown 语法,alt 必填(无障碍 + 暗色降亮依据):

<p class="fig-cap">图:外滩的傍晚</p> ← 显式图注类(居中小字)
- 图注可选;必须用
<p class="fig-cap">…</p>(2026-11-02 起) - ⚠️ 旧写法
*斜体独立段*已不再自动当图注:此前它会把正文里所有独占成段的斜体都变成块级居中(用户实测的排版 bug),现在斜体恢复为正常行内强调 - 压缩纪律:入仓前长边 ≤2400px(可跑
python3 scripts/photos_ingest.py,对 posts 资产同样有效的思路,图片请自行用同规格压缩)
视频 / 音频
markdown 原生不认视音频,写 HTML 标签;raw HTML 的相对路径不走 Astro
资产管线(只有 ![]() 图片语法走),所以媒体文件放 public/media/{slug}/
(构建原样拷入 dist),引用用绝对路径 /media/...:
public/media/my-post/clip.mp4 ← 文件放这里
<video controls preload="metadata" src="/media/my-post/clip.mp4"></video>
*片头三秒试拍*
<audio controls preload="metadata" src="/media/my-post/voice.mp3"></audio>
*朗读:面纱选段*
preload="metadata"必写(不预拖流量,只取时长/首帧)- 图注警示:斜体图注行内不要裸写
<video>/<audio>字样——markdown 会把它渲染成真实元素(黑盒+吞文字),提及时用反引号 ` - 样式已全局处理(视频全宽圆角黑底、音频胶囊条)
- /media/ 命名空间同时覆盖"仓内小文件"与"仓外 store 大文件"(见体积纪律表)
体积纪律(git 仓红线)
| 媒体 | 入仓上限 | 超限怎么办 |
|---|---|---|
| 图片 | 单张 ≤1MB(2400px 压缩后通常 200-800KB) | 重压 |
| 音频 | ≤5MB(3 分钟 128kbps ≈ 2.8MB) | 降码率 |
| 视频 | ≤5MB | 放仓外 ~/docker_apps/blog/media/(photos-originals 同模式),文章里用绝对路径 /media/xxx.mp4;build.sh 同步段待该场景首次出现时补 |
历史教训:21 张原图 196M 直接入仓曾撞死推送通道(git 历史
7a2880b重写才甩掉)。
三媒齐用的样例
见 content/posts/media-sample.md(draft 文章,仅构建验证用,不上线)。
链接卡片(OG 预览卡)
一行只放一个链接、且它独立成段时,构建期会抓取该页的 OG 信息渲染成卡片(标题 / 描述 / 站点图标 / 可选缩略图):
https://astro.build/
[也可以是 markdown 链接形态](https://astro.build/)
规则与边界:
- 内联链接不变:夹在句子里的链接保持普通样式(
这是一句带 [链接](https://example.com) 的话→ 不会变卡),所以不会把整篇变成卡片墙 - 抓取失败一律回落普通链接:404、无 OG、超时(4s)、站点拒爬都不影响构建
- 每篇最多 10 张卡,超出的回落普通链接(防止文章变卡片流)
- 缓存:结果存
content/.link-cache.json(入仓,保证构建确定性);条目 30 天后自动重抓。想强制刷新某条——删掉该 URL 的条目即可 - 缩略图取
og:image,无图不占位;图标取站点而非第三方 favicon 服务
文章排版类(受限白名单)
正文里可用 <span class="…"> / <p class="…"> 做受限排版。构建期有白名单过滤:只放行下表类名,其它 class 与 style、on* 属性一律被剥离(防注入 + 保护灰阶骨架)。
灰阶层级类(全部实测亮暗对比度 ≥4.5:1)
| 类名 | 作用 |
|---|---|
ink-1 / ink-2 / ink-3 |
指定灰阶层(标题/正文/次要) |
ink-muted |
最淡灰(注释感) |
ink-faint |
最淡可读档(再淡即不达 AA) |
ink-warm |
暖调正文(书评气质) |
ink-cool |
冷调正文(技术气质) |
ink-accent |
强调(链接色,少量点缀) |
ink-accent-soft |
弱强调(比强调淡一档) |
语义色板(8 色相 × 标准/soft;亮暗各自取值,实测全部 ≥4.5:1)
| 色相 | 标准类 | soft 类 | 亮态对比度(标准 / soft) | 暗态(标准 / soft) |
|---|---|---|---|---|
| 蓝 | c-blue |
c-blue-soft |
6.46 / 4.58 | 7.70 / 4.61 |
| 青 | c-teal |
c-teal-soft |
5.00 / 4.57 | 9.77 / 4.52 |
| 绿 | c-green |
c-green-soft |
5.38 / 4.67 | 10.38 / 4.67 |
| 黄 | c-yellow |
c-yellow-soft |
6.45 / 4.57 | 11.73 / 4.52 |
| 橙 | c-orange |
c-orange-soft |
6.26 / 4.65 | 9.44 / 4.58 |
| 红 | c-red |
c-red-soft |
6.68 / 4.55 | 7.51 / 4.50 |
| 粉 | c-pink |
c-pink-soft |
6.96 / 4.73 | 8.87 / 4.52 |
| 紫 | c-purple |
c-purple-soft |
7.46 / 4.53 | 8.25 / 4.64 |
- 黄色在亮态被压暗到
#7a5900(原色在白底只有 ~1.8:1),这是必须的:彩色文字要能读 soft档是"阈值内最淡值",适合次要强调;标准档用于关键强调
使用纪律(重要):彩色只作用于文章正文的强调文字。站点外壳(导航、页脚、按钮、背景、卡片边框)一律保持灰阶——整站不因正文用色而花掉。写作时一个页面里的彩色强调建议不超过 3 处。
字体类
| 类名 | 作用 | 字体 | 许可证 | 加载 |
|---|---|---|---|---|
font-serif |
书评正文族 | Noto Serif SC | OFL-1.1 | 自托管 |
font-kai |
金句族 | 霞鹜文楷 Screen | OFL-1.1 | 自托管 |
font-sans |
UI/技术族 | Noto Sans SC | OFL-1.1 | 自托管 |
font-mono |
标签/数值 | JetBrains Mono | OFL-1.1 | 自托管 |
font-song |
宋体族 | Noto Serif SC 优先,系统宋体兜底 | OFL-1.1 | 自托管优先 |
font-kai-sys |
楷体族 | 霞鹜文楷优先,系统楷体兜底 | OFL-1.1 | 自托管优先 |
font-hei-sys |
黑体族 | Noto Sans SC 优先,系统黑体兜底 | OFL-1.1 | 自托管优先 |
font-fangsong |
仿宋族 | FangSong/STFangsong | — | ⚠️ 纯系统回退(暂无 OFL 自托管仿宋包) |
文学排版类(段落级)
| 类名 | 作用 |
|---|---|
drop-cap |
段落首字下沉(书评开篇) |
quote-line |
金句块(左侧竖线 + 文楷) |
fig-cap |
图注(居中小字) |
首批字体(已落地,6 族 + 3 档自托管优先)
| 类名 | 字体 | 许可证 | webfont 嵌入 | 用到该字体的页面增量 |
|---|---|---|---|---|
font-serif |
Noto Serif SC | OFL-1.1 | ✅ OFL 允许 | 基线内 |
font-sans |
Noto Sans SC | OFL-1.1 | ✅ | 基线内 |
font-kai |
霞鹜文楷 Screen | OFL-1.1 | ✅ | 基线内 |
font-mono |
JetBrains Mono | OFL-1.1 | ✅ | 基线内 |
font-huiwen |
汇文明朝体(文风切片包 339 片) | OFL-1.1 | ✅ | 535KB |
font-kuaile |
站酷快乐体 | OFL-1.1 | ✅ | 163KB |
font-song / font-kai-sys / font-hei-sys |
上述自托管字体优先,系统字族兜底 | OFL-1.1 | ✅ | +0KB |
体积账结论(2026-11-02 实测,本地无 gzip 的相对值):未使用某字体的页面,字体字节增量恒为 0(构建期按页子集化 + unicode-range 按需拉取)。汇文采用文风开源的 cn-font-split 切片包(339 片),实测只拉用到字符的 19 片。
候补字体清单(未落地,加一款约"一条命令 + 一次体积账")
| 字体 | 许可证 | 允许 webfont 嵌入 | 未落地原因 |
|---|---|---|---|
| HarmonyOS Sans | 华为字体许可(免费商用) | ✅ 明文允许"嵌入、捆绑、重新分发",需标注 | npm 无包,官网整包 52MB |
| MiSans | 小米字体许可(免费商用) | ✅ 官方 FAQ 明确 "embedded fonts: Yes",需注明 | npm 无包 |
| OPPO Sans | 免费授权(含商用) | ✅(附带"不向他方提供下载渠道"限制) | npm 无包 |
| 阿里巴巴普惠体 | 免费商用全场景 | ✅ | npm 无包,9 字重体积巨大 |
| 得意黑 Smiley Sans | OFL-1.1 | ✅ | 仅 GitHub release 整包,直链在当前网络不可达 |
| 更纱黑体 Sarasa Gothic / Sarasa Mono | OFL-1.1 | ✅ | npm 包为空壳(需 cli 自生成切片) |
| 花园明朝 HanaMinA/B | IPA Font License | ✅(允许嵌入) | 无 npm 包,仅兜底用 |
| 站酷高端黑 / 站酷快乐体(已落) | OFL-1.1 | ✅ | 高端黑无 @fontsource 版本 |
| 阿里妈妈东方大楷 / 演示悠然小楷 | 免费商用 / 个人免费 | ⚠️ 需逐款核嵌入条款 | 无包;"个人免费"字体常禁 @font-face |
| 霞鹜文楷 Light/Bright | OFL-1.1 | ✅ | 实测 +8605KB(CJK 切片粒度所致) |
加新字体的流程:①核许可证与 web 嵌入条款(很多"个人免费"字体明文禁 @font-face,只能进系统回退)②npm 装或放入
public/fonts/<family>/(优选 cn-font-split 类切片包)③global.css加类 +rehype-class-whitelist放行 +public/admin/typography-classes.js加一项 ④跑体积账,超 150KB/页 的要评估是否值得。
<span class="ink-muted">次要说明</span>
<span class="font-kai">金句可以换文楷</span>
<p class="drop-cap">开篇段落,首字会下沉。</p>
<p class="quote-line">所谓暮色,就是光慢慢地承认自己要走。</p>
- 颜色只能走上面这些类(内部用 tokens,亮暗双态都可读);写
style="color:red"会被构建期剔除 - 斜体就用普通 markdown
*斜体*——行内强调,不会换行也不会居中
后台可视化选择(推荐,不用写 HTML)
后台编辑器里:选中文字 → Insert 菜单 → 「排版(字体/颜色)」→ 面板里点一个类,文字即被 <span class="…"> 包住;点已套用的片段可改类,Backspace 可整体删除。
面板里的两类与上表一一对应(字体 8 / 颜色 9),类清单单一事实源在 public/admin/typography-classes.js。
发布提醒
- push main → webhook 自动构建发布(约 10 秒)
- 新文章要英文版:跑
python3 scripts/translate/translate_posts.py(幂等,代码块不会被翻译破坏的风险见其 README 注释;锁定润色用 frontmatterlocked: true)
书封图(/books 书架)
阅读轨文章可选加书封:
- 图片放
content/posts/assets/books/<slug>.jpg(建议宽 480px、高宽比约 2:3) - 对应文章 frontmatter 加一行:
cover: ./assets/books/<slug>.jpg - 构建自动优化出 96/192 两档;没有 cover 的文章优雅回退现有色脊卡设计,无需改任何代码
示例 frontmatter:
---
title: "面纱"
pubDate: 2024-06-01
category: reading
bookAuthor: "毛姆"
mood: "#8a6f4a"
cover: ./assets/books/mian-sha.jpg
---
后台上传(Sveltia 后台,推荐路径)
后台地址 /admin/(gitea 账号登录)。三类媒体都有后台入口,不必手写路径:
图片
文章编辑器里插入图片 → 自动上传到 content/posts/assets/ 并写入 ./assets/...
相对路径(走 Astro 图片管线,自动优化)。不要手改成 /assets/... 绝对路径。
视频(frontmatter 字段,正文后自动渲染)
- 文章编辑页「附视频」字段上传(自动落
public/media/,路径写/media/<name>.mp4) - 正文读完后自动出现
<video controls preload="metadata" playsinline>,全宽圆角黑底 - 「视频封面」填
/media/xxx.jpg可自定首帧;留空浏览器自取 - 无视频字段 → 该区块不渲染(零占位)
体积纪律:mp4/webm ≤50MB 走 public/media/(构建原样拷贝,不转码);
更大的请按上文「体积纪律」放仓外 store(该场景 build.sh 同步段待首次出现时补)。
后台列表日期
文章/瞬间列表显示「日期 · 标题」,可按日期排序;图库照片没有 frontmatter 日期 (时间在 EXIF/文件侧),列表按「分组 · 标题」展示、按标题/分组排序。
链接
markdown 原生语法,无需任何配置:
[文字](https://example.com)
想让链接显示成 OG 预览卡(带标题/描述/图标),把它单独放一行即可——规则见上文「链接卡片(OG 预览卡)」。
页面文案(主页/关于/开源)
后台「页面文案」下三个入口:
| 入口 | 文件 | 可改内容 |
|---|---|---|
| 主页设置 | content/site/home.yaml |
身份语 tagline、头像 avatar、站点图标 favicon、社交链接 socials |
| 关于页 | content/site/about.yaml |
markdown 正文 intro(多段/列表/粗斜体/链接) |
| 开源页 | content/site/opensource.yaml |
叙述 blurb/blurb_after、仓链接、置顶项目 pinned |
头像与站点图标
- 头像:主页设置里「头像」上传 → 落
content/site/assets/,构建期优化成 60px WebP; 留空则显示内置渐变占位(w4 徽标) - 站点图标 favicon:先经「图标」媒体库上传(
public/icons/),再把路径粘到 「站点图标」字段(如/icons/my.ico、/icons/my.svg);留空回退/favicon.svg。 支持.svg/.ico/.png(直出,不经图片优化)
社交链接
主页设置里「社交链接」是列表:可增删、拖动排序。每条 = 名称(无障碍文字)+ 链接 + 图标。
图标可选 github / rss / email / bilibili / x,留空则显示纯文字按钮。
首页名片区、以及任何引用该组件的页面都吃同一份数据(单一事实源,改一次全站生效)。
首页可配项(home.yaml)
| 字段 | 取值 | 默认 | 作用 |
|---|---|---|---|
subtitle |
{zh, en}(markdown 短文本) |
空 | 身份语下方的副标题;留空不渲染 |
latestPhotos |
0-6 | 4 | 「最新影像」张数;0 = 隐藏该区块 |
perTrackLimit |
4-8 | 6 | 首页阅读/技术两轨各显示条数 |
sections |
{tracks, photos, heatmap, projects} 布尔 |
全开 | 区块开关,关掉即不渲染 |
越界值会被夹取(如 perTrackLimit=20 按 8 处理),不报错;全部留空 = 现有形态不变。
开源页项目墙(opensource.yaml)
| 字段 | 取值 | 默认 | 作用 |
|---|---|---|---|
mode |
all / only / exclude |
all | 可见性模式 |
include |
仓短名数组 | 空 | mode=only 时的白名单 |
exclude |
仓短名数组 | 空 | mode=exclude 时的黑名单 |
sort |
pinned-first / stars / updated |
pinned-first | 排序方式 |
perSource |
both / github / gitea |
both | 来源过滤 |
intro_from |
"off" / github-readme |
off | 开篇文案来源 |
intro_from建议带引号写:YAML 1.1 里裸off会被解析成布尔 false。 选github-readme时构建期取wait4xx/wait4xx的 README 渲染为开篇, 成功后缓存到content/.github-readme.md(入仓);token 缺位/取失败/仓无 README 都会打印日志并回落 yaml 的 blurb。注意 README 里的相对链接与外部徽章会原样输出。
首页文章列表
首页现在分两段:阅读轨 6 条 + 技术轨 6 条(各自带「全部文章」出口:阅读→书架、技术→归档)。
照片轨文章不进首页(在图库看)。完整列表见 /archives/。
- 中文/英文各一个字段,页面按语言取;留空则该字段回落默认文案(构建不会炸)
pinned填仓库短名(如blog、pi-board),顺序即展示顺序;留空回落blog