feat(typography): 全站三层排版——富文本/页面级覆盖/艺术字体类
- 层 1 所有页面文案改富文本:site-content 新增 renderRich(md,{inline})
复用既有全管线(raw→内容净化→class 白名单→链接卡片);接入
home.tagline/subtitle、opensource.blurb、about.intro、blocks prose;
新增 .rich 容器作用域并与 .prose-body 合并(77 处选择器覆盖四类容器)
坑:renderRich 输出 <p> 塞进 <p class="tagline"> 会被浏览器拆散 →
行内场景用 {inline:true} 剥外层 <p>
- 层 2 页面级排版覆盖:三单例加 typography{font?,accent?,scale?},读取器
pageTypography() 走白名单(10 字族 / 18 色类,scale 夹 0.8–1.25,清单外
忽略);页面容器挂 .page-typo + CSS 变量 --page-font/--page-accent/
--page-scale,不动全站 tokens;后台三页加「页面排版覆盖」下拉
- 层 3 艺术字体:新增 font-art-kuaile(快乐体专用类,字距微调),白名单与
可视化面板同步;站酷高端黑/阿里妈妈东方大楷/演示悠然小楷因无 npm 包或
嵌入条款风险进候补清单
- 默认值清理:about.yaml 的 typography 测试值(整页汇文)清为注释示例——
整页换字族会带来 694KB 字体成本,默认留空=全站默认排版
验证: 构建 48 页 exit 0;E2E 37/37;三页 page-typo 挂载与变量实测、四页
(图库/书架/文章/装备)隔离为 0、font-art-kuaile 生效、about 清空后
无覆盖
Spec: none (排版三层,先于 5g 的任务;T3/T4 另行交付)
Co-authored-by: GLM-5.3
This commit is contained in:
1 parent
2f7cbcf7bd
commit
aaa9cd9274
10 files changed
+136
-48
No files matched your search
@@ -82,6 +82,9 @@ intro:
|
||||
This is the public workbench of my three tracks: **books** that left notes, **code** that reaches the project wall, and **shutters** I pressed that land in the gallery.
|
||||
|
||||
# 页面级排版覆盖(层 2)
|
||||
typography:
|
||||
font: font-huiwen
|
||||
accent: c-red
|
||||
# 页面级排版覆盖(后台「关于页 → 页面排版覆盖」可改):
|
||||
# 整页换字族会带来字体体积成本(如 font-huiwen 整页 ≈694KB),默认留空=全站默认排版
|
||||
# typography:
|
||||
# font: font-huiwen # 字族:font-serif/font-sans/font-kai/font-huiwen/font-kuaile…
|
||||
# accent: c-red # 强调色类:c-blue/c-red/…(外壳仍灰阶)
|
||||
# scale: 1.05 # 字号缩放 0.8–1.25
|
||||
@@ -185,6 +185,32 @@ https://astro.build/
|
||||
后台编辑器里:**选中文字 → Insert 菜单 → 「排版(字体/颜色)」→ 面板里点一个类**,文字即被 `<span class="…">` 包住;点已套用的片段可改类,Backspace 可整体删除。
|
||||
面板里的两类与上表一一对应(字体 8 / 颜色 9),类清单单一事实源在 `public/admin/typography-classes.js`。
|
||||
|
||||
## 三层排版架构(全站,不只文章正文)
|
||||
|
||||
**层 1 · 页面文案富文本**:后台「页面文案」里的 tagline / subtitle / blurb / blurb_after / intro / 关于页 blocks 的 prose 块,全部走同一条富文本管线(markdown + raw + 内容净化 + class 白名单 + 链接卡片)。可以直接写:
|
||||
|
||||
```yaml
|
||||
tagline:
|
||||
zh: '<span class="font-kai c-blue">写作者</span> · 读者 · 快门按压者,拥抱开源。'
|
||||
```
|
||||
|
||||
渲染入口唯一:`src/lib/site-content.ts` 的 `renderRich()`(行内场景传 `{ inline: true }` 自动剥外层 `<p>`,否则 `<p>` 套 `<p>` 会被浏览器拆散)。
|
||||
**不开放**:导航/页脚/按钮等硬编码界面外壳——那是 UI 不是内容。
|
||||
|
||||
**层 2 · 页面级排版覆盖**:每个页面单例(`content/site/*.yaml`)可加:
|
||||
|
||||
```yaml
|
||||
typography:
|
||||
font: font-kai # 本页正文默认字体类(可选)
|
||||
accent: c-blue # 本页强调色类(可选)
|
||||
scale: 1.1 # 字号缩放 0.8–1.25(可选)
|
||||
```
|
||||
|
||||
实现是在该页内容容器上挂 `.page-typo` + CSS 变量(`--page-font / --page-accent / --page-scale`),**不写全站 tokens**——其它页面零影响(已在图库/书架/文章/装备页验证隔离)。白名单外的类名会被忽略。
|
||||
后台入口:「页面文案 → 各自页面 → 页面排版覆盖」。
|
||||
|
||||
**层 3 · 艺术字体**:`font-art-kuaile`(站酷快乐体,艺术字专用类)。⚠️ **仅用于标题/短句**:艺术字字形大,CJK 切片体积高(实测用到页 +163KB),长段使用会显著抬高单页字体成本。
|
||||
|
||||
## 发布提醒
|
||||
|
||||
- push main → webhook 自动构建发布(约 10 秒)
|
||||
|
||||
@@ -18,6 +18,7 @@ window.TYPOGRAPHY_CLASSES = {
|
||||
{ cls: 'font-fangsong', label: '仿宋族', family: 'FangSong, STFangsong, serif', kind: '系统回退' },
|
||||
{ cls: 'font-huiwen', label: '汇文明朝体', family: '"WF-Hwmc", serif', kind: '自托管' },
|
||||
{ cls: 'font-kuaile', label: '站酷快乐体', family: '"ZCOOL KuaiLe", serif', kind: '自托管' },
|
||||
{ cls: 'font-art-kuaile', label: '快乐体(艺术·仅标题)', family: '"ZCOOL KuaiLe", serif', kind: '艺术字' },
|
||||
],
|
||||
color: [
|
||||
{ cls: 'ink-1', label: '最重(标题级)', swatch: '#111113' },
|
||||
|
||||
@@ -205,6 +205,29 @@ export const collections = {
|
||||
.optional(),
|
||||
}),
|
||||
}),
|
||||
// 主题旋钮(样式即数据 · 层 4):只放 9 组白名单旋钮,钳制与单调性在 src/lib/theme.ts
|
||||
siteTheme: defineCollection({
|
||||
loader: glob({ pattern: 'theme.yaml', base: './content/site' }),
|
||||
schema: z.object({
|
||||
accent_light: z.string().optional(),
|
||||
accent_dark: z.string().optional(),
|
||||
radius_img: z.number().optional(),
|
||||
text_h1: z.number().optional(),
|
||||
text_h2: z.number().optional(),
|
||||
text_h3: z.number().optional(),
|
||||
prose_size_reading: z.number().optional(),
|
||||
prose_size_tech: z.number().optional(),
|
||||
leading_reading: z.number().optional(),
|
||||
leading_tech: z.number().optional(),
|
||||
space_3: z.number().optional(),
|
||||
space_4: z.number().optional(),
|
||||
space_5: z.number().optional(),
|
||||
space_6: z.number().optional(),
|
||||
flow_p: z.number().optional(),
|
||||
flow_h2_post: z.number().optional(),
|
||||
dur: z.number().optional(),
|
||||
}),
|
||||
}),
|
||||
siteAbout: defineCollection({
|
||||
loader: glob({ pattern: 'about.yaml', base: './content/site' }),
|
||||
// intro = 多段 markdown 正文(二级回退:blocks 为空时才用)
|
||||
|
||||
@@ -46,6 +46,7 @@ const ALLOWED = new Set([
|
||||
'font-fangsong',
|
||||
'font-huiwen',
|
||||
'font-kuaile',
|
||||
'font-art-kuaile',
|
||||
// 文学排版
|
||||
'drop-cap',
|
||||
'quote-line',
|
||||
|
||||
@@ -8,7 +8,7 @@ import PostList from '../../components/PostList.astro';
|
||||
import ProjectWall from '../../components/geek/ProjectWall.astro';
|
||||
import Heatmap from '../../components/geek/Heatmap.astro';
|
||||
import { t } from '../../i18n/ui';
|
||||
import { homeConfig, homeTagline, renderMarkdown } from '../../lib/site-content';
|
||||
import { homeConfig, homeTagline, pageTypography, renderMarkdown, renderRich } from '../../lib/site-content';
|
||||
import SocialLinks from '../../components/SocialLinks.astro';
|
||||
|
||||
// 首页可配项(后台主页设置):副标题/影像张数/区块开关/每轨条数,字段级回落
|
||||
@@ -24,11 +24,14 @@ const enTitle = Object.fromEntries(
|
||||
const photos = (await getCollection('photos')).slice(0, Math.max(1, cfg.latestPhotos));
|
||||
// 身份语与 zh 版同源(content/site/home.yaml 的 en 字段),缺值回落默认
|
||||
const tagline = await homeTagline('en');
|
||||
const taglineHtml = await renderRich(tagline, { inline: true });
|
||||
const typo = await pageTypography('siteHome', 'home');
|
||||
---
|
||||
|
||||
<BaseLayout title="wait4x" description="wait4x's blog: reading · code · photography">
|
||||
<div class={typo.className || undefined} style={typo.style || undefined}>
|
||||
<IdCard>
|
||||
<p class="tagline">{tagline}</p>
|
||||
<p class="tagline rich" set:html={taglineHtml} />
|
||||
{subtitleHtml && <div class="subtitle" set:html={subtitleHtml} />}
|
||||
<SocialLinks />
|
||||
</IdCard>
|
||||
@@ -66,6 +69,7 @@ const tagline = await homeTagline('en');
|
||||
}}
|
||||
/>}
|
||||
{cfg.sections.projects && <ProjectWall locale="en" />}
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -3,25 +3,30 @@ import ProjectWall from '../../components/geek/ProjectWall.astro';
|
||||
import Heatmap from '../../components/geek/Heatmap.astro';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { t } from '../../i18n/ui';
|
||||
import { githubReadmeMarkdown, openSourceCopy, openSourceOptions, renderMarkdown } from '../../lib/site-content';
|
||||
import { githubReadmeMarkdown, openSourceCopy, openSourceOptions, pageTypography, renderMarkdown, renderRich } from '../../lib/site-content';
|
||||
|
||||
const copy = await openSourceCopy('en');
|
||||
const options = await openSourceOptions();
|
||||
const readmeMd = options.introFrom === 'github-readme' ? await githubReadmeMarkdown() : null;
|
||||
const readmeHtml = readmeMd ? await renderMarkdown(readmeMd) : null;
|
||||
const blurbHtml = await renderRich(copy.blurb, { inline: true });
|
||||
const blurbAfterHtml = await renderRich(copy.blurbAfter, { inline: true });
|
||||
const typo = await pageTypography('siteOpenSource', 'opensource');
|
||||
---
|
||||
<BaseLayout title="Open Source · wait4x" description="My open-source activity: repos, contributions, and this site's source">
|
||||
<h1 class="page-title">Open Source</h1>
|
||||
<div class={typo.className || undefined} style={typo.style || undefined}>
|
||||
{readmeHtml ? (
|
||||
<div class="blurb readme-intro" set:html={readmeHtml} />
|
||||
) : (
|
||||
<p class="blurb">{copy.blurb}<a class="link" href={copy.repoUrl}>{copy.repoLabel}</a>{copy.blurbAfter}</p>
|
||||
<p class="blurb rich" set:html={`${blurbHtml}<a class="link" href="${copy.repoUrl}">${copy.repoLabel}</a>${blurbAfterHtml}`} />
|
||||
)}
|
||||
<Heatmap labels={{
|
||||
title: t('heatmap_title', 'en'), summary: t('heatmap_summary', 'en'),
|
||||
less: t('heatmap_less', 'en'), more: t('heatmap_more', 'en'), note: t('heatmap_note', 'en'),
|
||||
}} />
|
||||
<ProjectWall limit={99} locale="en" pinned={copy.pinned} options={options} />
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -6,6 +6,7 @@ import IdCard from '../components/IdCard.astro';
|
||||
import PostList from '../components/PostList.astro';
|
||||
import ProjectWall from '../components/geek/ProjectWall.astro';
|
||||
import Heatmap from '../components/geek/Heatmap.astro';
|
||||
import { pageTypography, renderRich } from '../lib/site-content';
|
||||
import { fetchHeartbeat, agoZh } from '../lib/heartbeat';
|
||||
import { t } from '../i18n/ui';
|
||||
import { homeConfig, homeTagline, renderMarkdown } from '../lib/site-content';
|
||||
@@ -22,11 +23,15 @@ const photos = (await getCollection('photos')).slice(0, Math.max(1, cfg.latestPh
|
||||
const heartbeat = await fetchHeartbeat();
|
||||
// 身份语改由 content/site/home.yaml 供给(后台可改),缺值回落默认文案
|
||||
const tagline = await homeTagline('zh');
|
||||
// 层 1:tagline 走富文本(后台可写 <span class="font-kai c-blue">)
|
||||
const taglineHtml = await renderRich(tagline, { inline: true });
|
||||
const typo = await pageTypography('siteHome', 'home');
|
||||
---
|
||||
|
||||
<BaseLayout title="wait4x">
|
||||
<div class={typo.className || undefined} style={typo.style || undefined}>
|
||||
<IdCard>
|
||||
<p class="tagline">{tagline}</p>
|
||||
<p class="tagline rich" set:html={taglineHtml} />
|
||||
{subtitleHtml && <div class="subtitle" set:html={subtitleHtml} />}
|
||||
<SocialLinks />
|
||||
</IdCard>
|
||||
@@ -73,6 +78,7 @@ const tagline = await homeTagline('zh');
|
||||
最近心跳:{agoZh(heartbeat.when)} · {heartbeat.msg}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -3,7 +3,7 @@ import ProjectWall from '../components/geek/ProjectWall.astro';
|
||||
import Heatmap from '../components/geek/Heatmap.astro';
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import { t } from '../i18n/ui';
|
||||
import { githubReadmeMarkdown, openSourceCopy, openSourceOptions, renderMarkdown } from '../lib/site-content';
|
||||
import { githubReadmeMarkdown, openSourceCopy, openSourceOptions, pageTypography, renderMarkdown, renderRich } from '../lib/site-content';
|
||||
|
||||
// 叙述文案 + 置顶名单 + 项目墙选项均改由 content/site/opensource.yaml 供给(后台可改)
|
||||
const copy = await openSourceCopy('zh');
|
||||
@@ -11,19 +11,25 @@ const options = await openSourceOptions();
|
||||
// 开篇来源:github-readme → 构建期取 profile 仓 README(缓存 content/.github-readme.md,失败回落 yaml blurb)
|
||||
const readmeMd = options.introFrom === 'github-readme' ? await githubReadmeMarkdown() : null;
|
||||
const readmeHtml = readmeMd ? await renderMarkdown(readmeMd) : null;
|
||||
// 层 1:blurb 两段走统一富文本管线(后台可写 <span class="font-kai c-blue">)
|
||||
const blurbHtml = await renderRich(copy.blurb, { inline: true });
|
||||
const blurbAfterHtml = await renderRich(copy.blurbAfter, { inline: true });
|
||||
const typo = await pageTypography('siteOpenSource', 'opensource');
|
||||
---
|
||||
<BaseLayout title="开源 · wait4x" description="我的开源活动:仓库、贡献与本站源码">
|
||||
<h1 class="page-title">开源<span class="count mono">Open Source</span></h1>
|
||||
<div class={typo.className || undefined} style={typo.style || undefined}>
|
||||
{readmeHtml ? (
|
||||
<div class="blurb readme-intro" set:html={readmeHtml} />
|
||||
) : (
|
||||
<p class="blurb">{copy.blurb}<a class="link" href={copy.repoUrl}>{copy.repoLabel}</a>{copy.blurbAfter}</p>
|
||||
<p class="blurb rich" set:html={`${blurbHtml}<a class="link" href="${copy.repoUrl}">${copy.repoLabel}</a>${blurbAfterHtml}`} />
|
||||
)}
|
||||
<Heatmap labels={{
|
||||
title: t('heatmap_title', 'zh'), summary: t('heatmap_summary', 'zh'),
|
||||
less: t('heatmap_less', 'zh'), more: t('heatmap_more', 'zh'), note: t('heatmap_note', 'zh'),
|
||||
}} />
|
||||
<ProjectWall limit={99} pinned={copy.pinned} options={options} />
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
|
||||
+51
-38
@@ -148,7 +148,7 @@ pre code { background: none; border: none; padding: 0; font-size: inherit; }
|
||||
}
|
||||
/* 图注:**显式类驱动**(`<p class="fig-cap">说明</p>`)。此前按 `p > em:only-child` 自动命中,
|
||||
把正文里任何独占成段的斜体都变成块级居中——用户实测的排版 bug(斜体单独一行并居中)由此而来。 */
|
||||
.prose-reading p.fig-cap, .prose-tech p.fig-cap,
|
||||
.prose-reading p.fig-cap, .prose-tech p.fig-cap, .rich p.fig-cap, .prose-body p.fig-cap,
|
||||
.prose-reading p.fig-cap em, .prose-tech p.fig-cap em {
|
||||
display: block;
|
||||
text-align: center;
|
||||
@@ -167,60 +167,66 @@ pre code { background: none; border: none; padding: 0; font-size: inherit; }
|
||||
}
|
||||
/* ── 受限排版类(文章内通过 <span class> 使用;rehype 白名单只放行这些类名) ──
|
||||
颜色一律走 tokens,亮暗双态都可读;禁任意 hex/内联样式(保持灰阶骨架)。 */
|
||||
.prose-reading .ink-1, .prose-tech .ink-1 { color: var(--ink-1); }
|
||||
.prose-reading .ink-2, .prose-tech .ink-2 { color: var(--ink-2); }
|
||||
.prose-reading .ink-3, .prose-tech .ink-3 { color: var(--ink-3); }
|
||||
.prose-reading .ink-muted, .prose-tech .ink-muted { color: var(--ink-4); }
|
||||
.prose-reading .ink-accent, .prose-tech .ink-accent { color: var(--accent); }
|
||||
.prose-reading .ink-accent-soft, .prose-tech .ink-accent-soft { color: var(--accent-soft-text); }
|
||||
.prose-reading .ink-warm, .prose-tech .ink-warm { color: var(--ink-warm); }
|
||||
.prose-reading .ink-cool, .prose-tech .ink-cool { color: var(--ink-cool); }
|
||||
.prose-reading .ink-faint, .prose-tech .ink-faint { color: var(--ink-faint); }
|
||||
.prose-reading .ink-1, .prose-tech .ink-1, .rich .ink-1, .prose-body .ink-1 { color: var(--ink-1); }
|
||||
.prose-reading .ink-2, .prose-tech .ink-2, .rich .ink-2, .prose-body .ink-2 { color: var(--ink-2); }
|
||||
.prose-reading .ink-3, .prose-tech .ink-3, .rich .ink-3, .prose-body .ink-3 { color: var(--ink-3); }
|
||||
.prose-reading .ink-muted, .prose-tech .ink-muted, .rich .ink-muted, .prose-body .ink-muted { color: var(--ink-4); }
|
||||
.prose-reading .ink-accent, .prose-tech .ink-accent, .rich .ink-accent, .prose-body .ink-accent { color: var(--accent); }
|
||||
.prose-reading .ink-accent-soft, .prose-tech .ink-accent-soft, .rich .ink-accent-soft, .prose-body .ink-accent-soft { color: var(--accent-soft-text); }
|
||||
.prose-reading .ink-warm, .prose-tech .ink-warm, .rich .ink-warm, .prose-body .ink-warm { color: var(--ink-warm); }
|
||||
.prose-reading .ink-cool, .prose-tech .ink-cool, .rich .ink-cool, .prose-body .ink-cool { color: var(--ink-cool); }
|
||||
.prose-reading .ink-faint, .prose-tech .ink-faint, .rich .ink-faint, .prose-body .ink-faint { color: var(--ink-faint); }
|
||||
/* 语义色板:彩色只作用于正文强调(站点外壳保持灰阶)。
|
||||
每色相两档:标准 / soft(阈值内最淡);亮暗各取独立值,均实测 ≥4.5:1。 */
|
||||
.prose-reading .c-blue, .prose-tech .c-blue { color: var(--c-blue); }
|
||||
.prose-reading .c-blue-soft, .prose-tech .c-blue-soft { color: var(--c-blue-soft); }
|
||||
.prose-reading .c-teal, .prose-tech .c-teal { color: var(--c-teal); }
|
||||
.prose-reading .c-teal-soft, .prose-tech .c-teal-soft { color: var(--c-teal-soft); }
|
||||
.prose-reading .c-green, .prose-tech .c-green { color: var(--c-green); }
|
||||
.prose-reading .c-green-soft, .prose-tech .c-green-soft { color: var(--c-green-soft); }
|
||||
.prose-reading .c-yellow, .prose-tech .c-yellow { color: var(--c-yellow); }
|
||||
.prose-reading .c-yellow-soft, .prose-tech .c-yellow-soft { color: var(--c-yellow-soft); }
|
||||
.prose-reading .c-orange, .prose-tech .c-orange { color: var(--c-orange); }
|
||||
.prose-reading .c-orange-soft, .prose-tech .c-orange-soft { color: var(--c-orange-soft); }
|
||||
.prose-reading .c-red, .prose-tech .c-red { color: var(--c-red); }
|
||||
.prose-reading .c-red-soft, .prose-tech .c-red-soft { color: var(--c-red-soft); }
|
||||
.prose-reading .c-pink, .prose-tech .c-pink { color: var(--c-pink); }
|
||||
.prose-reading .c-pink-soft, .prose-tech .c-pink-soft { color: var(--c-pink-soft); }
|
||||
.prose-reading .c-purple, .prose-tech .c-purple { color: var(--c-purple); }
|
||||
.prose-reading .c-purple-soft, .prose-tech .c-purple-soft { color: var(--c-purple-soft); }
|
||||
.prose-reading .font-serif, .prose-tech .font-serif { font-family: var(--font-serif); }
|
||||
.prose-reading .font-kai, .prose-tech .font-kai { font-family: var(--font-kai); }
|
||||
.prose-reading .font-sans, .prose-tech .font-sans { font-family: var(--font-sans); }
|
||||
.prose-reading .font-mono, .prose-tech .font-mono { font-family: var(--font-mono); font-size: 0.92em; }
|
||||
.prose-reading .c-blue, .prose-tech .c-blue, .rich .c-blue, .prose-body .c-blue { color: var(--c-blue); }
|
||||
.prose-reading .c-blue-soft, .prose-tech .c-blue-soft, .rich .c-blue-soft, .prose-body .c-blue-soft { color: var(--c-blue-soft); }
|
||||
.prose-reading .c-teal, .prose-tech .c-teal, .rich .c-teal, .prose-body .c-teal { color: var(--c-teal); }
|
||||
.prose-reading .c-teal-soft, .prose-tech .c-teal-soft, .rich .c-teal-soft, .prose-body .c-teal-soft { color: var(--c-teal-soft); }
|
||||
.prose-reading .c-green, .prose-tech .c-green, .rich .c-green, .prose-body .c-green { color: var(--c-green); }
|
||||
.prose-reading .c-green-soft, .prose-tech .c-green-soft, .rich .c-green-soft, .prose-body .c-green-soft { color: var(--c-green-soft); }
|
||||
.prose-reading .c-yellow, .prose-tech .c-yellow, .rich .c-yellow, .prose-body .c-yellow { color: var(--c-yellow); }
|
||||
.prose-reading .c-yellow-soft, .prose-tech .c-yellow-soft, .rich .c-yellow-soft, .prose-body .c-yellow-soft { color: var(--c-yellow-soft); }
|
||||
.prose-reading .c-orange, .prose-tech .c-orange, .rich .c-orange, .prose-body .c-orange { color: var(--c-orange); }
|
||||
.prose-reading .c-orange-soft, .prose-tech .c-orange-soft, .rich .c-orange-soft, .prose-body .c-orange-soft { color: var(--c-orange-soft); }
|
||||
.prose-reading .c-red, .prose-tech .c-red, .rich .c-red, .prose-body .c-red { color: var(--c-red); }
|
||||
.prose-reading .c-red-soft, .prose-tech .c-red-soft, .rich .c-red-soft, .prose-body .c-red-soft { color: var(--c-red-soft); }
|
||||
.prose-reading .c-pink, .prose-tech .c-pink, .rich .c-pink, .prose-body .c-pink { color: var(--c-pink); }
|
||||
.prose-reading .c-pink-soft, .prose-tech .c-pink-soft, .rich .c-pink-soft, .prose-body .c-pink-soft { color: var(--c-pink-soft); }
|
||||
.prose-reading .c-purple, .prose-tech .c-purple, .rich .c-purple, .prose-body .c-purple { color: var(--c-purple); }
|
||||
.prose-reading .c-purple-soft, .prose-tech .c-purple-soft, .rich .c-purple-soft, .prose-body .c-purple-soft { color: var(--c-purple-soft); }
|
||||
.prose-reading .font-serif, .prose-tech .font-serif, .rich .font-serif, .prose-body .font-serif { font-family: var(--font-serif); }
|
||||
.prose-reading .font-kai, .prose-tech .font-kai, .rich .font-kai, .prose-body .font-kai { font-family: var(--font-kai); }
|
||||
.prose-reading .font-sans, .prose-tech .font-sans, .rich .font-sans, .prose-body .font-sans { font-family: var(--font-sans); }
|
||||
.prose-reading .font-mono, .prose-tech .font-mono, .rich .font-mono, .prose-body .font-mono { font-family: var(--font-mono); font-size: 0.92em; }
|
||||
/* 系统字族回退类:不下载字体,命中访客本机字体——跨设备不保证一致(docs 已注明) */
|
||||
/* 自托管优先 + 系统兜底(2026-11-02 口径):跨设备一致性由站内 webfont 保证,
|
||||
系统字族只作最后兜底;font-fangsong 暂无 OFL 自托管包,仍为纯系统回退(docs 已注明)。 */
|
||||
.prose-reading .font-song, .prose-tech .font-song {
|
||||
.prose-reading .font-song, .prose-tech .font-song, .rich .font-song, .prose-body .font-song {
|
||||
font-family: "Noto Serif SC Variable", "Noto Serif SC", "Songti SC", SimSun, serif;
|
||||
}
|
||||
.prose-reading .font-kai-sys, .prose-tech .font-kai-sys {
|
||||
.prose-reading .font-kai-sys, .prose-tech .font-kai-sys, .rich .font-kai-sys, .prose-body .font-kai-sys {
|
||||
font-family: "LXGW WenKai Screen", "Kaiti SC", STKaiti, KaiTi, serif;
|
||||
}
|
||||
.prose-reading .font-hei-sys, .prose-tech .font-hei-sys {
|
||||
.prose-reading .font-hei-sys, .prose-tech .font-hei-sys, .rich .font-hei-sys, .prose-body .font-hei-sys {
|
||||
font-family: "Noto Sans SC Variable", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
}
|
||||
.prose-reading .font-huiwen, .prose-tech .font-huiwen {
|
||||
.prose-reading .font-huiwen, .prose-tech .font-huiwen, .rich .font-huiwen, .prose-body .font-huiwen {
|
||||
font-family: 'WF-Hwmc', var(--font-serif);
|
||||
}
|
||||
.prose-reading .font-kuaile, .prose-tech .font-kuaile {
|
||||
.prose-reading .font-kuaile, .prose-tech .font-kuaile, .rich .font-kuaile, .prose-body .font-kuaile {
|
||||
font-family: 'ZCOOL KuaiLe', var(--font-serif);
|
||||
}
|
||||
.prose-reading .font-fangsong, .prose-tech .font-fangsong {
|
||||
/* 艺术字体专用类(层 3):仅用于标题/短句。艺术字字形大、CJK 切片体积高
|
||||
(实测 163KB/用到页),长段使用会显著抬高单页字体成本——docs 有体积警告。 */
|
||||
.prose-reading .font-art-kuaile, .prose-tech .font-art-kuaile, .rich .font-art-kuaile, .prose-body .font-art-kuaile {
|
||||
font-family: 'ZCOOL KuaiLe', var(--font-serif);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.prose-reading .font-fangsong, .prose-tech .font-fangsong, .rich .font-fangsong, .prose-body .font-fangsong {
|
||||
font-family: FangSong, STFangsong, "FangSong_GB2312", serif;
|
||||
}
|
||||
/* 文学常用:首字下沉(书评开篇)与金句块(引文式的独立强调段) */
|
||||
.prose-reading p.drop-cap::first-letter, .prose-tech p.drop-cap::first-letter {
|
||||
.prose-reading p.drop-cap::first-letter, .prose-tech p.drop-cap::first-letter, .rich p.drop-cap::first-letter, .prose-body p.drop-cap::first-letter {
|
||||
float: left;
|
||||
font-family: var(--font-serif);
|
||||
font-size: 3.1em;
|
||||
@@ -229,7 +235,7 @@ pre code { background: none; border: none; padding: 0; font-size: inherit; }
|
||||
margin-top: 0.05em;
|
||||
color: var(--paper-ink);
|
||||
}
|
||||
.prose-reading .quote-line, .prose-tech .quote-line {
|
||||
.prose-reading .quote-line, .prose-tech .quote-line, .rich .quote-line, .prose-body .quote-line {
|
||||
display: block;
|
||||
font-family: var(--font-kai);
|
||||
color: var(--paper-ink);
|
||||
@@ -327,3 +333,10 @@ html.reader .prose-reading, html.reader .prose-tech {
|
||||
}
|
||||
html.reader #main > * { animation: none; } /* 入场动效关闭 */
|
||||
/* ICP 备案链接永不隐藏(合规底线);分隔点号随之保留必要最小集 */
|
||||
|
||||
/* ── 层 2:页面级排版覆盖容器(只作用于当前页内容区,不动全站 tokens) ── */
|
||||
.page-typo {
|
||||
font-family: var(--page-font, inherit);
|
||||
font-size: calc(1em * var(--page-scale, 1));
|
||||
}
|
||||
.page-typo .page-accent, .page-typo .link { color: var(--page-accent, var(--accent)); }
|
||||
Reference in new issue
Block a user