diff --git a/assets/style.css b/assets/style.css
index 035fdfa..8d322ab 100644
--- a/assets/style.css
+++ b/assets/style.css
@@ -195,6 +195,8 @@ html.preload * {
html {
overflow-y: hidden; /* 改为hidden,移除强制显示的滚动条 */
scrollbar-width: thin; /* Firefox */
+ /* 明确 rem 基准字号:便于用 rem 统一管理字号(1rem = 16px) */
+ font-size: 16px;
}
/* 搜索高亮样式 */
@@ -208,8 +210,8 @@ html {
body {
- font-family: var(--font-body);
- font-weight: var(--font-weight-body);
+ font-family: var(--font-body, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "Helvetica Neue", Arial, sans-serif);
+ font-weight: var(--font-weight-body, normal);
line-height: 1.6;
background-color: var(--bg-color);
color: var(--text-color);
@@ -961,8 +963,6 @@ body .content.expanded {
}
.welcome-section h2 {
- font-family: var(--font-title);
- font-weight: var(--font-weight-title);
font-size: 2.4rem;
color: var(--text-bright);
margin-bottom: 0.5rem;
@@ -971,8 +971,8 @@ body .content.expanded {
}
.welcome-section h3 {
- font-family: var(--font-subtitle);
- font-weight: var(--font-weight-subtitle);
+ font-family: "Quicksand", var(--font-body, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "Helvetica Neue", Arial, sans-serif);
+ font-weight: 500;
font-size: 2rem;
margin-bottom: 1rem;
letter-spacing: 0.3px;
@@ -1496,7 +1496,7 @@ body .content.expanded {
}
.site-card.site-card-repo .repo-title {
- font-size: 1.05rem;
+ font-size: 1rem;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
@@ -1597,12 +1597,12 @@ body .content.expanded {
}
.site-card.site-card-large h3 {
- font-size: 1.05rem;
+ font-size: 1rem;
font-weight: 600;
}
.site-card.site-card-large p {
- font-size: 0.88rem;
+ font-size: 0.9rem;
}
/* Phase 2:articles 页面隐藏“扩展写回结构”,避免与文章条目渲染混淆 */
@@ -1809,7 +1809,7 @@ body .content.expanded {
}
.site-card h3 {
- font-size: 0.95rem;
+ font-size: 1rem;
margin-bottom: 0.25rem;
color: var(--text-bright);
font-weight: 500;
@@ -1822,7 +1822,7 @@ body .content.expanded {
}
.site-card p {
- font-size: 0.82rem;
+ font-size: 0.9rem;
color: var(--nav-item-color);
margin: 0;
line-height: 1.4;
@@ -2249,22 +2249,22 @@ body .content.expanded {
text-align: center;
}
- .site-card h3 {
- font-size: 0.95rem;
- margin-bottom: 0.4rem;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: 100%;
- }
-
- .site-card p {
- font-size: 0.85rem;
- line-height: 1.3;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
+ .site-card h3 {
+ font-size: 1rem;
+ margin-bottom: 0.4rem;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 100%;
+ }
+
+ .site-card p {
+ font-size: 0.9rem;
+ line-height: 1.3;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
/* 在移动端的主题切换按钮 */
.theme-toggle {
@@ -2347,22 +2347,22 @@ body .content.expanded {
font-size: 1.2rem;
}
- .site-card h3 {
- font-size: 0.9rem;
- margin-bottom: 0.3rem;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: 100%;
- }
+ .site-card h3 {
+ font-size: 1rem;
+ margin-bottom: 0.3rem;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 100%;
+ }
- .site-card p {
- font-size: 0.8rem;
- line-height: 1.2;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
+ .site-card p {
+ font-size: 0.9rem;
+ line-height: 1.2;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
}
@media (max-width: 400px) {
@@ -2405,22 +2405,22 @@ body .content.expanded {
font-size: 1.1rem;
}
- .site-card h3 {
- font-size: 0.85rem;
- margin-bottom: 0.25rem;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: 100%;
- }
-
- .site-card p {
- font-size: 0.75rem;
- line-height: 1.15;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
+ .site-card h3 {
+ font-size: 1rem;
+ margin-bottom: 0.25rem;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 100%;
+ }
+
+ .site-card p {
+ font-size: 0.9rem;
+ line-height: 1.15;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
}
/* 动画效果 */
diff --git a/config/README.md b/config/README.md
index c4e6a69..2fea5af 100644
--- a/config/README.md
+++ b/config/README.md
@@ -108,9 +108,9 @@ MeNav 配置系统采用“完全替换”策略(不合并),按以下优
- `manual`:完全使用手动 Font Awesome 图标,不发起外部请求(适合内网/离线/隐私敏感场景)
3. **字体**
- - `fonts.*.source: google | system`
- - `system`:使用系统字体,加载更快;`google`:可选字体更多但可能受网络影响
- - 中文站点建议选择支持中文与字重的字体(如 `Noto Sans SC`);请确保所选字体包含配置的字重,否则可能显示异常
+ - `fonts`:单一字体配置项,用于设置全站基础字体(`body` 等)
+ - 支持 `source: css | google | system`(分别表示第三方 CSS、Google Fonts、系统字体)
+ - 首页副标题(渐变发光样式)字体固定为 `Quicksand`,不通过配置项控制
4. **顶部欢迎信息与社交链接**
- `profile`:首页顶部欢迎信息
@@ -238,21 +238,14 @@ profile:
title: "个人导航站"
subtitle: "我收藏的精选网站"
-# 字体配置
+# 字体:全站基础字体
fonts:
- title:
- family: Roboto
- weight: 600
- source: google
- subtitle:
- family: Noto Sans SC
- weight: 500
- source: google
- body:
- family: Noto Sans SC
- weight: 400
- source: google
-
+ source: css
+ cssUrl: "https://fontsapi.zeoseven.com/292/main/result.css"
+ family: "LXGW WenKai"
+ weight: normal
+
+
# 社交媒体链接
social:
- name: "GitHub"
diff --git a/config/_default/site.yml b/config/_default/site.yml
index eace365..36e3b46 100644
--- a/config/_default/site.yml
+++ b/config/_default/site.yml
@@ -15,21 +15,23 @@ icons:
# 隐私提示:启用 favicon 模式会请求第三方服务以获取图标,可能将站点 URL 发送给服务商(详见 README“隐私说明”)。
mode: favicon # 可选: favicon | manual(默认 favicon)
-# 字体设置(source: google | system;请确保字体支持相应字重)
+# 字体设置:全站基础字体
+# - source: css | google | system
+# - css: 通过 cssUrl 引入第三方字体 CSS
+# - google: 通过 Google Fonts 加载 family(weight 建议 100~900)
+# - system: 只使用本地/系统字体,不额外发起请求
fonts:
- title:
- family: Poppins
- weight: 600
- source: google
- subtitle:
- family: Quicksand
- weight: 500
- source: google
- body:
- family: Noto Sans SC
- weight: 400
- source: google
-
+ source: css
+ cssUrl: "https://fontsapi.zeoseven.com/292/main/result.css"
+ family: LXGW WenKai
+ weight: normal
+
+# 示例:切换到 Google Fonts
+# fonts:
+# source: google
+# family: "Noto Sans SC"
+# weight: 400
+
# 个人资料:显示在首页顶部的欢迎信息
profile:
# 注意:首页(导航第一项)标题区优先使用 profile.title/profile.subtitle
diff --git a/src/generator.js b/src/generator.js
index 7714d2d..e29d984 100644
--- a/src/generator.js
+++ b/src/generator.js
@@ -291,23 +291,13 @@ function ensureConfigDefaults(config) {
// 确保基本结构存在
result.site = result.site || {};
result.navigation = result.navigation || [];
- result.fonts = result.fonts || {};
- // 确保字体配置完整
- result.fonts.title = result.fonts.title || {};
- result.fonts.title.family = result.fonts.title.family || 'Arial';
- result.fonts.title.weight = result.fonts.title.weight || 700;
- result.fonts.title.source = result.fonts.title.source || 'system';
-
- result.fonts.subtitle = result.fonts.subtitle || {};
- result.fonts.subtitle.family = result.fonts.subtitle.family || 'Arial';
- result.fonts.subtitle.weight = result.fonts.subtitle.weight || 500;
- result.fonts.subtitle.source = result.fonts.subtitle.source || 'system';
-
- result.fonts.body = result.fonts.body || {};
- result.fonts.body.family = result.fonts.body.family || 'Arial';
- result.fonts.body.weight = result.fonts.body.weight || 400;
- result.fonts.body.source = result.fonts.body.source || 'system';
+ // 字体默认值(单一字体配置)
+ result.fonts = result.fonts && typeof result.fonts === 'object' ? result.fonts : {};
+ result.fonts.source = result.fonts.source || 'css';
+ result.fonts.family = result.fonts.family || 'LXGW WenKai';
+ result.fonts.weight = result.fonts.weight || 'normal';
+ result.fonts.cssUrl = result.fonts.cssUrl || 'https://fontsapi.zeoseven.com/292/main/result.css';
result.profile = result.profile || {};
result.social = result.social || [];
@@ -1065,39 +1055,130 @@ ${searchSections}
`;
}
-// 生成Google Fonts链接
-function generateGoogleFontsLink(config) {
- const fonts = config.fonts;
- const googleFonts = [];
+/**
+ * 将 CSS 文本安全嵌入到 ` 结束标签导致样式块被提前终止。
+ * @param {string} cssText CSS 文本
+ * @returns {string} 安全的 CSS 文本
+ */
+function makeCssSafeForHtmlStyleTag(cssText) {
+ if (typeof cssText !== 'string') {
+ return '';
+ }
- // 收集需要加载的Google字体
- Object.values(fonts).forEach(font => {
- if (font.source === 'google') {
- const fontName = font.family.replace(/["']/g, '');
- const fontWeight = font.weight || 400;
- googleFonts.push(`family=${fontName}:wght@${fontWeight}`);
- }
- });
-
- return googleFonts.length > 0
- ? ``
- : '';
+ return cssText.replace(/<\/style/gi, '<\\/style');
}
-// 生成字体CSS变量
-function generateFontVariables(config) {
- const fonts = config.fonts;
- let css = ':root {\n';
+function normalizeFontWeight(input) {
+ if (input === undefined || input === null) return 'normal';
- Object.entries(fonts).forEach(([key, font]) => {
- css += ` --font-${key}: ${font.family};\n`;
- if (font.weight) {
- css += ` --font-weight-${key}: ${font.weight};\n`;
- }
- });
+ if (typeof input === 'number' && Number.isFinite(input)) {
+ return String(input);
+ }
- css += '}';
- return css;
+ const raw = String(input).trim();
+ if (!raw) return 'normal';
+
+ if (/^(normal|bold|bolder|lighter)$/i.test(raw)) return raw.toLowerCase();
+ if (/^[1-9]00$/.test(raw)) return raw;
+
+ return raw;
+}
+
+function normalizeFontFamilyForCss(input) {
+ const raw = String(input || '').trim();
+ if (!raw) return '';
+
+ const generics = new Set([
+ 'serif',
+ 'sans-serif',
+ 'monospace',
+ 'cursive',
+ 'fantasy',
+ 'system-ui',
+ 'ui-serif',
+ 'ui-sans-serif',
+ 'ui-monospace',
+ 'ui-rounded',
+ 'emoji',
+ 'math',
+ 'fangsong',
+ ]);
+
+ return raw
+ .split(',')
+ .map(part => part.trim())
+ .filter(Boolean)
+ .map(part => {
+ const unquoted = part.replace(/^['"]|['"]$/g, '').trim();
+ if (!unquoted) return '';
+ if (generics.has(unquoted)) return unquoted;
+
+ const needsQuotes = /\s/.test(unquoted);
+ if (!needsQuotes) return unquoted;
+
+ return `"${unquoted.replace(/"/g, '\\"')}"`;
+ })
+ .filter(Boolean)
+ .join(', ');
+}
+
+function normalizeFontSource(input) {
+ const raw = String(input || '').trim().toLowerCase();
+ if (raw === 'css' || raw === 'google' || raw === 'system') return raw;
+ return 'system';
+}
+
+function getNormalizedFontsConfig(config) {
+ const fonts =
+ config && config.fonts && typeof config.fonts === 'object' ? config.fonts : {};
+
+ return {
+ source: normalizeFontSource(fonts.source),
+ family: normalizeFontFamilyForCss(fonts.family),
+ weight: normalizeFontWeight(fonts.weight),
+ cssUrl: String(fonts.cssUrl || fonts.href || '').trim(),
+ };
+}
+
+// 生成字体相关 (包含固定的首页特殊样式字体)
+function generateFontLinks(config) {
+ const fonts = getNormalizedFontsConfig(config);
+ const links = [];
+
+ // 首页特殊样式字体:固定为 Quicksand(不通过配置控制)
+ links.push('');
+ links.push('');
+ links.push(
+ ''
+ );
+
+ // 全站基础字体:按配置加载
+ if (fonts.source === 'css' && fonts.cssUrl) {
+ links.push(
+ ``
+ );
+ }
+
+ if (fonts.source === 'google' && fonts.family) {
+ const familyNoQuotes = fonts.family.replace(/["']/g, '').split(',')[0].trim();
+ const weight = /^[1-9]00$/.test(fonts.weight) ? fonts.weight : '400';
+ const familyParam = encodeURIComponent(familyNoQuotes).replace(/%20/g, '+');
+ links.push(
+ ``
+ );
+ }
+
+ return links.join('\n');
+}
+
+// 生成字体 CSS 变量(单一字体配置)
+function generateFontCss(config) {
+ const fonts = getNormalizedFontsConfig(config);
+ const family = fonts.family || 'system-ui, sans-serif';
+ const weight = fonts.weight || 'normal';
+
+ const css = `:root {\n --font-body: ${family};\n --font-weight-body: ${weight};\n}\n`;
+ return makeCssSafeForHtmlStyleTag(css);
}
function normalizeGithubHeatmapColor(input) {
@@ -1322,11 +1403,9 @@ function generateHTML(config) {
return navItem;
});
- // 准备Google Fonts链接
- const googleFontsLink = generateGoogleFontsLink(config);
-
- // 准备CSS字体变量
- const fontVariables = generateFontVariables(config);
+ // 准备字体链接与 CSS 变量
+ const fontLinks = generateFontLinks(config);
+ const fontCss = generateFontCss(config);
// 准备社交链接
const socialLinks = generateSocialLinks(config.social);
@@ -1335,8 +1414,8 @@ function generateHTML(config) {
const layoutData = {
...config,
pages,
- googleFontsLink,
- fontVariables,
+ fontLinks,
+ fontCss,
navigationData,
currentYear,
socialLinks,
diff --git a/templates/layouts/default.hbs b/templates/layouts/default.hbs
index 12978cf..ff89bfd 100644
--- a/templates/layouts/default.hbs
+++ b/templates/layouts/default.hbs
@@ -9,20 +9,10 @@
- {{{googleFontsLink}}}
+ {{{fontLinks}}}
-
-
-
-
-
-
-
-
-
-