字体系统重做:脱离 Google Fonts,统一思源黑/宋,门面加霞鹜文楷

一、全部改走 jsdelivr 上的 Fontsource,不再依赖 Google Fonts
   之前文章页的 Inter / Noto Sans SC / Playfair Display / Noto Serif SC
   全部来自 fonts.googleapis.com —— 而文章页恰恰是最该稳的页面。
   现在 5 份样式表都由 BaseLayout 顶部的 fontStylesheets 统一声明。

二、CJK 用可变字体(关键)
   @fontsource-variable/noto-sans-sc 一份 CSS 覆盖 font-weight: 100 900,
   不用为 400/500/600/700 各加载一份(那样是 4 × 105 KB = 420 KB)。
   每份 CSS 内含约 100 条带 unicode-range 的 @font-face,浏览器只下载当前
   页面命中的分包。完整思源黑体 3.3 MB / 101 个分包,一页通常只用到 100–300 KB。

三、层次:楷(门面点睛)> 宋(标题)> 黑(正文/UI)
   - 正文/UI:思源黑体 Noto Sans SC Variable(两档都用)
   - 标题:思源宋体 Noto Serif SC Variable
   - 门面点睛:霞鹜文楷 LXGW WenKai(regular + bold)—— 用在站点名、
     首页那句话、以及 --font-display-sans 覆盖的卡片标题
   - 西文:Inter Variable(正文)+ Playfair Display(展示)
   霞鹜文楷只在 fontProfile="interface" 的页面加载;文章页没加载它,
   而 --font-display-sans 里它排在思源黑体前面,靠浏览器自动回退。

四、删掉鸿蒙 Sans
   两档现在都用思源黑体,所以 body.font-profile-interface 那条按档覆盖字族的
   规则删掉了。class 保留,它现在只用来决定是否加载文楷。

五、顺带修掉 --font-mono 断掉的回退链
   原来只有 "Geist Mono", "Geist Mono Fallback" —— 这两个名字既没有 @font-face
   也没装在机器上,等于整条回退链失效,浏览器退回默认字体(不是等宽)。
   全站几十处 font-mono(时间线日期、偶得时间戳、内联代码、灯箱说明…)都在受影响。
   补上 ui-monospace / SFMono-Regular / Menlo / Consolas / monospace。

体积账(gzip 后的样式表,和 .woff2 分包的实际下载是两回事)
   文章页  62.5 KB -> 64.6 KB
   门面   125.5 KB -> 127.4 KB
   基本持平,换来摆脱 Google Fonts + 字体统一 + 多一款文楷

验证:pnpm build 退出码 0
- 文章页只加载 Inter + Playfair + 思源黑 + 思源宋;首页额外加载文楷两档
- 两类页面里 Google Fonts 与鸿蒙均已消失
- 产物 CSS 里 5 个字族名与 ui-monospace 回退均在
- 站点名与首页那句话的 class 已带 font-display-sans
- 字体文件实测可下载(jsdelivr 相对路径解析正常)
This commit is contained in:
dsh
2026-09-17 19:35:12 +08:00
parent ef72d52de4
commit e92ee27818
6 changed files with 81 additions and 35 deletions
+24
View File
@@ -299,6 +299,30 @@ sudo sysctl fs.inotify.max_user_watches=524288
如果连空态提示都看不到,检查 `src/data/reading.json` 是否存在(这个文件要提交进 git)。
**想换字体 / 字体是从哪加载的**
全部由 `src/layouts/BaseLayout.astro` 顶部的 `fontStylesheets` 数组决定,
走 jsdelivr 上的 Fontsource 包(**不用 Google Fonts**,国内访问不稳):
| 层级 | 字体 | 用在哪 |
|---|---|---|
| 门面点睛(楷)| 霞鹜文楷 `LXGW WenKai` | 站点名、首页那句话、卡片标题 |
| 标题(宋)| 思源宋体 `Noto Serif SC Variable` | 文章标题、页面标题 |
| 正文/UI(黑)| 思源黑体 `Noto Sans SC Variable` | 文章正文、界面、按钮 |
| 西文 | `Inter Variable` + `Playfair Display` | 西文与数字、展示衬线 |
字族名的对应关系写在 `src/styles/global.css` 的 `--font-*` token 里。
改字体只需动这两处,不用碰组件。
两个要点:
- **CJK 用可变字体**(一份 CSS 覆盖 100–900 全字重),不要改成按字重加载 ——
那样每个字重一份 105 KB 的 CSS,四档就是 420 KB
- 每份 CSS 内含约 100 条带 `unicode-range` 的 `@font-face`,浏览器只下载当前页面
实际用到的那几个分包。完整思源黑体是 3.3 MB,但一页通常只命中 100–300 KB
- 霞鹜文楷**只在门面档加载**(`fontProfile="interface"`);文章页没加载它,
所以 `--font-display-sans` 里它排在思源黑体前面、由浏览器自动回退
**改了 markdown 插件却不生效**
Astro 会把渲染好的文章缓存到 `node_modules/.astro`,而这个缓存**只按 markdown
+1 -1
View File
@@ -175,7 +175,7 @@ export function Hero() {
*/}
<div className="hero-quote">
<h1
className={`hero-typewriter font-sans ${HERO_SIZE_CLASSES} font-bold tracking-tight text-foreground leading-[1.15] min-h-[1.2em] whitespace-nowrap`}
className={`hero-typewriter font-display-sans ${HERO_SIZE_CLASSES} font-bold tracking-tight text-foreground leading-[1.15] min-h-[1.2em] whitespace-nowrap`}
>
{renderText()}
</h1>
+1 -1
View File
@@ -36,7 +36,7 @@ const isCurrent = (href: string) =>
class="w-full h-full object-cover"
/>
</div>
<span class="text-foreground font-medium tracking-tight hidden sm:block">{site.name}</span>
<span class="font-display-sans text-foreground font-medium tracking-tight hidden sm:block">{site.name}</span>
</a>
{/* 字号只在 lg 以上放大:768–1023 这段页眉本来就挤(导航 + 搜索框 + 主题按钮
+1 -1
View File
@@ -1,5 +1,5 @@
{
"updatedAt": "2026-09-17T10:36:53.871Z",
"updatedAt": "2026-09-17T11:35:09.881Z",
"source": "weread",
"books": [
{
+35 -23
View File
@@ -41,7 +41,36 @@ const {
fontProfile = "reading",
} = Astro.props as Props
const useHarmonySans = fontProfile === "interface"
/** 门面档(首页、书架、专题、相册…)额外加载霞鹜文楷做点睛;文章页不需要 */
const isInterfaceProfile = fontProfile === "interface"
const FONTSOURCE_CDN = "https://cdn.jsdelivr.net/npm"
/*
* 字体清单。全部走 jsdelivr 上的 Fontsource 包,不再依赖 Google Fonts。
*
* - CJK 用**可变字体**:一份 CSS 覆盖 100–900 全字重,不用为 400/500/600/700
* 各下一份(那样是 4 × 105 KB)
* - 每份 CSS 内含约 100 条带 unicode-range 的 @font-face,浏览器只下载当前
* 页面实际用到的那几个分包,不是整包
* - 体积(gzip):文章页 ≈ 65 KB;门面再加文楷两档 ≈ 127 KB。
* 原来的 Google Fonts + 鸿蒙方案是 62.5 / 125.5 KB,基本持平
*/
const fontStylesheets = [
// 西文:正文与展示衬线
`${FONTSOURCE_CDN}/@fontsource-variable/inter@5/index.css`,
`${FONTSOURCE_CDN}/@fontsource/playfair-display@5/index.css`,
// 中文黑体(正文/UI)与宋体(标题)
`${FONTSOURCE_CDN}/@fontsource-variable/noto-sans-sc@5/index.css`,
`${FONTSOURCE_CDN}/@fontsource-variable/noto-serif-sc@5/index.css`,
// 门面点睛:霞鹜文楷(regular + bold)
...(isInterfaceProfile
? [
`${FONTSOURCE_CDN}/lxgw-wenkai-webfont@1.7.0/lxgwwenkai-regular.css`,
`${FONTSOURCE_CDN}/lxgw-wenkai-webfont@1.7.0/lxgwwenkai-bold.css`,
]
: []),
]
const canonicalUrl = canonical || Astro.url.toString()
const resolvedOgTitle = ogTitle || title
const resolvedOgDescription = ogDescription || description
@@ -70,27 +99,10 @@ const resolvedTwitterDescription = twitterDescription || description
<meta name="twitter:description" content={resolvedTwitterDescription} />
<slot name="head" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
{useHarmonySans ? <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin /> : null}
{useHarmonySans ? (
<>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/harmonyos-sans-sc-webfont-splitted@1.1.0/dist/Regular.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/harmonyos-sans-sc-webfont-splitted@1.1.0/dist/Semibold.css"
/>
</>
) : null}
<link
rel="stylesheet"
href={useHarmonySans
? "https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400..700;1,400..700&family=Noto+Serif+SC:wght@400..900&display=swap"
: "https://fonts.googleapis.com/css2?family=Inter:wght@400..700&family=Noto+Sans+SC:wght@400..700&family=Playfair+Display:ital,wght@0,400..700;1,400..700&family=Noto+Serif+SC:wght@400..900&display=swap"}
/>
{/* 字体全部走 jsdelivr 上的 Fontsource:CJK 用可变字体 + unicode-range 分包,
不再依赖 Google Fonts(国内访问不稳)。清单见上方 fontStylesheets。 */}
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
{fontStylesheets.map((href) => <link rel="stylesheet" href={href} />)}
<link rel="icon" href="/icon-light-32x32.png" media="(prefers-color-scheme: light)" />
<link rel="icon" href="/icon-dark-32x32.png" media="(prefers-color-scheme: dark)" />
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
@@ -212,7 +224,7 @@ const resolvedTwitterDescription = twitterDescription || description
</script>
<ClientRouter />
</head>
<body class:list={["bg-background text-foreground", { "font-profile-interface": useHarmonySans }]}>
<body class:list={["bg-background text-foreground", { "font-profile-interface": isInterfaceProfile }]}>
<slot />
<ImageLightbox />
<script is:inline>
+19 -9
View File
@@ -163,12 +163,24 @@
}
@theme inline {
--font-sans: "Inter", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
--font-display-sans: "HarmonyOS Sans SC", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
--font-serif: "Noto Serif SC", "Source Han Serif SC", "Playfair Display", "Georgia", serif;
--font-serif-cn: "Noto Serif SC", "Source Han Serif SC", "Georgia", serif;
/*
* 字体由 BaseLayout.astro 的 fontStylesheets 从 jsdelivr(Fontsource)加载,
* 不再用 Google Fonts。CJK 都是可变字体,一份文件覆盖 100–900 全字重。
*
* 层次:楷(门面点睛)> 宋(标题)> 黑(正文/UI)
*/
--font-sans: "Inter Variable", "Noto Sans SC Variable", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
/* 霞鹜文楷只在门面档加载;文章页没加载它,会自动退回思源黑体,所以它排第二位 */
--font-display-sans: "LXGW WenKai", "Noto Sans SC Variable", "PingFang SC", "Microsoft YaHei", sans-serif;
--font-serif: "Noto Serif SC Variable", "Source Han Serif SC", "Playfair Display", "Georgia", serif;
--font-serif-cn: "Noto Serif SC Variable", "Source Han Serif SC", "Georgia", serif;
--font-display-serif: "Playfair Display", "Georgia", serif;
--font-mono: "Geist Mono", "Geist Mono Fallback";
/*
* 原来只写了 "Geist Mono", "Geist Mono Fallback" —— 这两个名字既没有 @font-face
* 也没装在机器上,等于把 font-mono 的回退链断掉了,浏览器只能退回默认字体(不是等宽)。
* 全站几十处 font-mono(时间线日期、偶得时间戳、内联代码…)都受影响。
*/
--font-mono: "Geist Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-surface-subtle: var(--surface-subtle);
@@ -245,10 +257,8 @@
}
}
body.font-profile-interface,
body.font-profile-interface .font-sans {
font-family: "HarmonyOS Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
}
/* 两档现在都用思源黑体,不再需要按档覆盖字族。
font-profile-interface 这个 class 保留 —— 它现在只决定是否额外加载霞鹜文楷。 */
/* Custom smooth scrolling (avoid hash navigation animation) */
html {