Resume-Matcher 简历模板设计规范全解:Swiss 国际主义风格的设计系统与源码实现
【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters & more, locally with 100+ LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher
本文以 docs/agent/design/resume-template-design-spec.md 为核心,系统拆解 Resume-Matcher 前端模板系统中 Swiss 国际主义风格(Swiss International Style)简历模板的设计规范,包括排版、间距、色彩、章节顺序、双栏布局、CSS 类体系与打印分页约束,并结合仓库中
swiss-single(单栏)与swiss-two-column(双栏)两套模板的源码与样式文件,说明规范如何落地为可运行的 React 组件与 CSS Modules。读完本文,你将能理解这套规范的全部设计参数,掌握其在源码中的对应实现位置,并学会通过模板设置项定制间距、字号、页边距等视觉变量。
Resume-Matcher 是一套本地化运行的 AI 简历工作台,提供简历构建、PDF 导出、求职信与岗位匹配等能力;其前端内置多套简历模板,其中swiss-single是默认模板。本文聚焦的这份设计规格书正是这两套瑞士风格模板的"设计宪法"——所有排版、间距、色彩与分页行为都围绕它展开。
一、规范定位:一份面向模板实现者的设计规格
resume-template-design-spec.md是一份非常精炼的设计规格书,副标题即点明其性质:Swiss International Style specifications for resume templates。它不是面向最终用户的操作手册,而是面向实现简历模板的工程师/Agent 的"约束清单"——任何新模板(或对现有模板的修改)都必须满足其中的排版参数、色彩取值、章节顺序与打印规则。
该规格在仓库中的配套文档还有两份更具体的实现说明:
- docs/agent/design/templates/swiss-single-spec.md:单栏模板实现规格(ID:
swiss-single); - docs/agent/design/templates/swiss-two-column-spec.md:双栏模板实现规格(ID:
swiss-two-column)。
规格对应的真实模板类型定义在 apps/frontend/lib/types/template-settings.ts 中,TemplateType联合类型包含swiss-single、swiss-two-column、modern、modern-two-column、latex、clean、vivid七种,默认模板即为swiss-single。React 组件导出则集中在 apps/frontend/components/resume/index.ts,其中ResumeSingleColumn与ResumeTwoColumn是本文讨论的两套瑞士风格实现。
二、Typography:排版规范与系统字体栈
规格书首先用一张表定义了六类元素的字体族、字号与字重,这是整个瑞士风格"少即是多"气质的根基:
| Element | Font | Size | Weight |
|---|---|---|---|
| Name(姓名) | serif | 2xl | bold |
| Title(职位头衔) | serif | lg | normal |
| Section heading(章节标题) | serif | lg | semibold |
| Job title(职位名) | sans | base | semibold |
| Company(公司名) | sans | sm | medium |
| Body text(正文) | sans | sm | normal |
| Metadata(元信息) | mono | xs | normal |
2.1 三种字族的落地:serif / sans / mono
规格中的 serif、sans、mono 在实现层面映射为 apps/frontend/components/resume/styles/_base.module.css 顶部定义的系统字体栈 CSS 变量:
--header-font:ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif,用于姓名、章节标题;--body-font:ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',用于正文、职位名、公司名;--resume-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace,定义在 apps/frontend/components/resume/styles/_tokens.css,用于日期、元信息等.resume-meta、.resume-date元素。
设计要点:正文与标题分属 sans / serif 两种字族,而元信息(年份、地点、技能标签)统一使用等宽字体,形成"信息密度 vs 视觉层级"的双重对比——这正是瑞士国际主义风格"用字体分类信息"的典型手法。
2.2 字号缩放机制:CSS 变量驱动的比例系统
规格书用抽象级别(2xl / lg / base / sm / xs)描述字号,实现则通过"基准字号 × 缩放系数"的 CSS 变量机制落地,见 _base.module.css:
.resume-name { font-size: calc(var(--font-size-base) * var(--header-scale)); /* 默认 14px × 2 = 28px */ font-family: var(--header-font); font-weight: 700; color: var(--resume-text-primary); } .resume-section-title { font-size: calc(var(--font-size-base) * var(--section-header-scale)); /* 默认 14px × 1.2 = 16.8px */ font-family: var(--header-font); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; border-bottom: 1px solid var(--resume-border-primary); }--font-size-base默认14px,--header-scale默认2,--section-header-scale默认1.2,与 swiss-single-spec.md 中 "Name: 2em (28px)、Section Header: 1.2em" 的数值完全对应。这套变量由 template-settings.ts 中的映射表驱动:
FONT_SIZE_MAP:基准字号五档11px / 12px / 14px / 15px / 16px(默认第 3 档);HEADER_SCALE_MAP:姓名缩放系数五档1.5 / 1.75 / 2 / 2.25 / 2.5(默认 2);SECTION_HEADER_SCALE_MAP:章节标题缩放系数五档1.0 / 1.1 / 1.2 / 1.3 / 1.4(默认 1.2);HEADER_FONT_MAP/BODY_FONT_MAP:标题与正文字族在serif、sans-serif、mono之间切换的字体栈映射。
字体设置还会在双栏模板中产生变体:侧栏章节标题使用.resume-section-title-sm,字号为base × section-header-scale × 0.88,比主栏略小以保证侧栏信息密度;对应源码见 _base.module.css 中.resume-section-title-sm的定义。
2.3 细节:字重与大小写的实现
规格表中 Section heading 定义为 semibold,实现中.resume-section-title使用font-weight: 700,并配合text-transform: uppercase(全大写)与letter-spacing: 0.05em(字距拉开)强化章节的视觉分割;而职位副标题类元素(.resume-item-subtitle)使用font-weight: 600,公司名(.resume-item-subtitle内联渲染)则与职位名同级呈现。单栏与双栏组件中,姓名统一为.resume-name并附加uppercase tracking-tight(Tailwind 工具类)实现紧凑大写效果,见 resume-single-column.tsx 与 resume-two-column.tsx 的 Header 渲染段。
三、Spacing:间距规范与可调档位
规格书定义的间距基线如下:
| Element | Spacing |
|---|---|
| Between sections(章节间距) | 16-24px |
| Between items(条目间距) | 8-12px |
| Line height(行高) | 1.4-1.6 |
实现层面,间距被抽象为两个 CSS 变量与一个行高变量,声明在 _base.module.css:
.resume-body { --section-gap: 1rem; /* 章节间距默认 16px */ --item-gap: 0.25rem; /* 条目间距默认 4px */ --line-height: 1.35; /* 行高默认 1.35 */ --margin-top: 10mm; --margin-bottom: 10mm; --margin-left: 10mm; --margin-right: 10mm; }用户可在"格式化控制"面板(formatting-controls.tsx)中通过 5 档间距设置调整这些变量,映射关系见 template-settings.ts:
SECTION_SPACING_MAP:章节间距五档6 / 10 / 16 / 20 / 24px(默认 16px,即 1rem,与规格 16-24px 区间吻合);ITEM_SPACING_MAP:条目间距五档2 / 4 / 8 / 12 / 16px(默认 4px);LINE_HEIGHT_MAP:行高五档1.15 / 1.25 / 1.35 / 1.45 / 1.55(默认 1.35,规格推荐 1.4-1.6,实现范围覆盖到 1.55 档)。
说明:规格书给出的 16-24px / 8-12px / 1.4-1.6 是"设计建议区间",而实现通过五档枚举让用户在更广范围内调节,默认值则取在区间内的最稳妥档位(章节 16px、行高 1.35 与规格下限接近)。如需接近规格上限,可选择第 4、5 档。
间距的消费方式贯穿组件:.resume-section使用margin-bottom: var(--section-gap);.resume-items、.resume-stack使用gap: var(--item-gap);.resume-item使用margin-bottom: var(--item-gap),且末子元素归零。双栏布局的列间空隙同样使用var(--section-gap),保证横纵间距视觉一致(见下文双栏小节)。
3.1 compactMode:一键压缩
模板设置中还有compactMode(紧凑模式)开关,其实现也落在 template-settings.ts 的settingsToCssVars函数中:开启后章节/条目间距乘以COMPACT_MULTIPLIER = 0.6,行高乘以更温和的COMPACT_LINE_HEIGHT_MULTIPLIER = 0.92(避免文本重叠),页边距不参与压缩。这为"一页简历"诉求提供了比规格基线更紧的间距档。
四、Colors:色彩令牌与主题切换
规格书用代码块定义了四色体系:
Text: #000000 (Ink) Links: #1D4ED8 (Hyper Blue) Dividers: #E5E5E0 Background: #FFFFFF这四色在设计层面是"黑白 + 一个高亮蓝 + 一个浅灰分隔线"的极简组合,符合瑞士风格对色彩克制的追求。实现层面的落地位于 _tokens.css,该文件是所有模板共享的"色彩令牌层":
.resume-body { --resume-text-primary: #000000; --resume-text-secondary: #374151; /* gray-700 */ --resume-text-tertiary: #4b5563; /* gray-600 */ --resume-text-body: #1f2937; /* gray-800 */ --resume-border-primary: #9ca3af; /* gray-400 */ --resume-border-secondary: #d1d5db;/* gray-300 */ --resume-border-tertiary: #e5e7eb; /* gray-200 */ --resume-accent-bg: #f3f4f6; /* gray-100 */ --resume-accent-primary: #1d4ed8; /* blue - default */ --resume-accent-light: #dbeafe; /* blue light - default */ }对应关系如下:
- 正文主色
Text #000000→--resume-text-primary(姓名、条目标题、链接使用); - 链接色
Links #1D4ED8→--resume-accent-primary(同时作为 Modern 等模板的主题强调色); - 分隔线
Dividers #E5E5E0→--resume-border-tertiary: #e5e7eb(色值近似,作为最浅一级边框); - 背景
#FFFFFF→.resume-body未显式设置背景色,默认继承页面白色背景。
值得注意的是,令牌系统为"黑白底 + 强调色"扩展了完整的灰阶:次级文字、三级文字、三级边框、强调底色各司其职,保证打印灰度下的可读性。强调色还支持主题切换——ACCENT_COLOR_MAP定义了blue / green / orange / red四套primary + light配色(默认 blue),由settingsToCssVars在运行时注入--resume-accent-primary与--resume-accent-light变量,供强调色模板动态换肤。单栏模板的分隔线还用在 Header 底部边框:style={{ borderColor: 'var(--resume-border-primary)' }},见 resume-single-column.tsx 的<header>渲染。
五、Section Order:章节顺序与动态渲染机制
规格书规定了 6 个标准章节的固定顺序:
- Header(姓名、职位、联系方式)
- Summary(个人摘要)
- Work Experience(工作经历)
- Projects(项目)
- Education(教育背景)
- Additional(技能、语言、证书、奖项)
该顺序在代码中的"权威默认值"是 apps/frontend/lib/utils/section-helpers.ts 里的DEFAULT_SECTION_META:personalInfo(0) → summary(1) → workExperience(2) → education(3) → personalProjects(4) → additional(5)。注意这里默认元数据把 Education 排在 Projects 之前,而规格书把 Projects 排在 Education 之前——实际渲染顺序由每个简历的sectionMeta决定,用户可以在 Builder 中拖拽调整。
5.1 排序与可见性
getSortedSections()是模板组件实际消费的排序入口:从sectionMeta过滤isVisible的章节后按order升序排列;同时getSectionMeta()在简历缺少sectionMeta时回退到默认元数据。单栏组件 resume-single-column.tsx 通过sortedSections.map(renderSection)按顺序渲染除personalInfo(作为 Header 单独处理)外的所有章节。
此外,章节标题支持 i18n 本地化:localizeDefaultSectionMeta()只对仍保留英文默认名的内置章节翻译标题(如 Summary → 摘要),不会覆盖用户的自定义命名;对应实现同样在 section-helpers.ts,与多语言消息文件(apps/frontend/messages/zh.json 等)配合。
5.2 自定义章节
除 6 个内置章节外,系统支持用户创建自定义章节(isDefault: false),通过createCustomSection()生成custom_<N>形式的 ID 并追加到章节列表末尾,渲染时由DynamicResumeSection(dynamic-resume-section.tsx)按sectionType动态渲染。这就是"Additional(技能/语言/证书/奖项)"之外可以无限扩展的第五个维度,规格书中的顺序约定因此成为"默认顺序"而非"硬编码顺序"。
六、Two-Column Layout:双栏布局与侧栏分工
规格书用 ASCII 图明确了双栏的空间分配与内容分工:
┌────────────────────┬──────────┐ │ Main (65%) │ Side 35% │ ├────────────────────┼──────────┤ │ Experience │ Summary │ │ Projects │ Education│ │ Certifications │ Skills │ │ │ Languages│ │ │ Awards │ └────────────────────┴──────────┘其设计意图是:主栏承载"招聘者最关心的经历信息",侧栏承载"支撑性信息",适配技术岗与一页简历。
6.1 网格实现
该布局在 apps/frontend/components/resume/styles/swiss-two-column.module.css 中实现为 CSS Grid:
.grid { display: grid; grid-template-columns: 65% 35%; /* Main column 65%, Sidebar 35% */ gap: var(--section-gap); margin-top: var(--section-gap); align-items: start; } .mainColumn { display: flex; flex-direction: column; gap: var(--section-gap); padding-right: 0.875rem; border-right: 1px solid var(--resume-border-tertiary); overflow: hidden; } .sidebarColumn { display: flex; flex-direction: column; gap: var(--section-gap); padding-left: 0.75rem; overflow: hidden; min-width: 0; }细节设计值得注意:
grid-template-columns: 65% 35%与规格图的 65/35 完全一致;- 主栏右侧通过
border-right: 1px solid var(--resume-border-tertiary)实现垂直分隔线(对应 swiss-two-column-spec 中 "Main column has border-right using --resume-border-tertiary"); - 两栏均设置
overflow: hidden防止内容溢出;侧栏设置min-width: 0确保窄列中日期等white-space: nowrap元素不会把网格撑破; align-items: start让两栏顶部对齐而非拉伸等高。
6.2 主栏 / 侧栏的源码分工
双栏组件 resume-two-column.tsx 的渲染逻辑与规格图一一对应:
- 主栏(左):Summary → Work Experience → Projects → Certifications/Training → 自定义章节;
- 侧栏(右):Education → Skills(
.resume-skill-pill药丸标签)→ Languages(join(' • ')点分隔)→ Awards → Links(LinkedIn/GitHub/Website 链接列表)。
侧栏还使用了两套适配窄列的样式:.resume-section-title-sm(小号章节标题)与.sidebar-text-wrap(word-break: break-word; overflow-wrap: break-word; hyphens: auto三件套,防止长单词撑破侧栏)。
6.3 单栏是"退化的双栏"
单栏模板 resume-single-column.tsx 的容器类.container仅设width: 100%(见 swiss-single.module.css),所有布局交由基础类的纵向堆叠完成;Additional 章节则以"标签 + 逗号分隔"的横向行(Technical Skills: a, b, c)形式呈现,而不是侧栏的药丸。两份配套规格分别将其描述为"最大内容密度、适合详细经历描述"(单栏)与"空间效率优先、适合技术岗一页简历"(双栏)——它们共享同一套字体/间距/色彩令牌,只在布局结构上分叉。
七、CSS Classes:类体系全览
规格书给出了四个核心类的语义:
.resume-section /* Section wrapper 章节容器 */ .resume-section-title /* Heading 章节标题 */ .resume-items /* Item container 条目容器 */ .resume-item /* Single entry 单个条目 */这四个类只是整个体系的"骨架",_base.module.css 中围绕它们建立了一套完整且自洽的类族,按职责可分为五组:
| 组别 | 类名 | 作用 |
|---|---|---|
| 容器 | .resume-body、.resume-header、.resume-section、.resume-items、.resume-item | 简历容器(含页边距 padding)、页眉、章节、条目列表、单条目 |
| 标题 | .resume-name、.resume-title、.resume-section-title、.resume-section-title-sm、.resume-item-title、.resume-item-title-sm、.resume-item-subtitle、.resume-item-subtitle-sm | 姓名/职位/章节标题/条目标题/副标题,含主栏与侧栏两种尺寸 |
| 正文 | .resume-text、.resume-text-sm、.resume-text-xs、.resume-meta、.resume-meta-sm、.resume-date | 正文三档字号、等宽元信息、右对齐日期(white-space: nowrap防止换行) |
| 列表 | .resume-stack、.resume-stack-tight、.resume-list、.resume-row、.resume-row-tight | 纵向 flex 堆叠与行距控制,间距均为var(--item-gap)的倍数 |
| 特殊 | .resume-skill-pill、.resume-link-pill、.resume-link、.sidebar-text-wrap、.text-muted | 技能药丸、链接药丸(项目 GitHub/网站)、内联链接、侧栏换行、弱化文字 |
这些类通过 CSS Modules 的baseStyles['resume-item-title']形式在组件中引用(如 resume-single-column.tsx 中工作经历条目title + company + bullet list的经典组合:.resume-item-title与右侧.resume-date同行 baseline 对齐,公司名与地点居中一行,描述为带•圆点的.resume-list)。富文本内容(加粗、斜体、下划线、内联链接)通过:global()选择器统一兜底,保证编辑器产物在简历中的样式一致。
八、Print Considerations:打印与分页的工程细节
规格书对打印输出提出三条硬性规则:
- Never split
.resume-itemacross pages:单个条目严禁跨页断裂; - Never orphan section headers:章节标题严禁成为页尾孤行;
- Minimum 50% page fill before break:分页前页面至少填充 50%(即避免过早分页造成大量留白)。
这三条规则在 _base.module.css 中均有对应的工程化实现,且分为"常态声明"与"打印强化"两层。
8.1 常态防断裂声明
.resume-item { margin-bottom: var(--item-gap); break-inside: avoid; page-break-inside: avoid; -webkit-column-break-inside: avoid; -moz-column-break-inside: avoid; } .resume-section-title { break-after: avoid; /* 标题后不换页 */ page-break-after: avoid; orphans: 3; /* 段首至少保留 3 行 */ widows: 3; /* 段尾至少保留 3 行 */ }break-inside: avoid系列属性保证条目整体跨页,break-after: avoid保证标题与后续内容同页,orphans/widows: 3则从排版层面避免标题、段落被切出孤行。
8.2 打印强化块
文件底部有一段完整的@media print块,用!important强化上述规则并补齐边界情况:
@media print { .resume-body { page-break-inside: avoid !important; break-inside: avoid-page !important; } .resume-item { break-inside: avoid !important; page-break-inside: avoid !important; } .resume-section-title, .resume-section-title-sm { break-after: avoid !important; page-break-after: avoid !important; } /* 标题与其第一个条目/段落/列表保持同页 */ .resume-section-title + .resume-items > *:first-child, .resume-section-title + p, .resume-section-title + ul, .resume-section-title + .resume-item { break-before: avoid !important; ... } /* 富文本格式与链接在 PDF 中强制还原 */ .resume-body :global(a) { color: inherit !important; text-decoration: underline !important; } }"Minimum 50% page fill" 属于内容排版纪律而非纯 CSS 可强制项,其实际约束由打印预览页(apps/frontend/app/print/resumes/[id]/page.tsx)与 PDF 渲染管线(后端 apps/backend/app/pdf.py)配合实现,工程师在写长条目时需人为控制内容密度,让分页点落在页面中后部。可参考 docs/agent/design/print-pdf-design-spec.md 与 docs/agent/design/pdf-template-guide.md 了解完整打印/PDF 设计约束。
九、从规范到可运行模板:配置、渲染与验证链路
9.1 设置默认值与 CSS 变量注入
模板设置的默认值定义在 template-settings.ts 的DEFAULT_TEMPLATE_SETTINGS:
{ template: 'swiss-single', // 默认单栏模板 pageSize: 'A4', // 页面尺寸 A4 / LETTER margins: { top: 10, bottom: 10, left: 10, right: 10 }, // 单位 mm spacing: { section: 3, item: 2, lineHeight: 3 }, // 均为 1-5 档 fontSize: { base: 3, headerScale: 3, headerFont: 'serif', bodyFont: 'sans-serif' }, compactMode: false, showContactIcons: false, // 联系方式是否显示图标 accentColor: 'blue', }这些设置在运行时由settingsToCssVars()统一转换为 CSS 自定义属性(--section-gap、--font-size-base、--margin-top等),以内联样式注入.resume-body,从而同时作用于屏幕预览(Builder 与 resume-component.tsx)和 PDF 打印渲染——这是"所见即所得"的关键机制:一份设置、两条渲染路径共享同一套 CSS 变量。
9.2 模板选择与字体预设
用户通过 template-selector.tsx 切换模板,TEMPLATE_OPTIONS中的Single Column(swiss-single)与Two Column(swiss-two-column)描述即对应本文的两套瑞士模板。切换时调用applyTemplatePreset()处理模板的"签名字体":latex、clean等单字型模板会强制预设其标志性字族,而瑞士双模板不在预设表中,切换时保留用户当前的字体设置。
9.3 测试保障
模板注册的完整性由 apps/frontend/tests/template-registration.test.ts 守护,它验证每个TemplateType都有对应的可渲染组件注册;组件级渲染正确性则由 resume-clean.test.tsx、resume-latex.test.tsx 等模板测试及 apps/frontend/tests/template-registration.test.ts 覆盖。后端侧还有 apps/backend/tests/integration/test_pdf_render.py 验证 PDF 渲染管线,确保打印输出与屏幕预览一致。
十、给模板贡献者的实践清单
综合规格书与源码实现,若要新增或修改一套符合规范的瑞士风格模板,应逐项对照以下检查点:
- 字族:姓名/章节标题使用
--header-font(serif),正文/职位使用--body-font(sans),日期/元信息使用--resume-font-mono; - 字号:以
--font-size-base为基准,通过--header-scale(默认 2)与--section-header-scale(默认 1.2)等比缩放,不要写死像素值; - 间距:章节间距消费
--section-gap,条目间距消费--item-gap,行高消费--line-height,避免引入第三个硬编码间距; - 色彩:文字一律取
--resume-text-primary等令牌,分隔线取--resume-border-tertiary,强调色取--resume-accent-primary,禁止硬编码十六进制色值; - 章节:遵循 6 内置章节 + 自定义章节模型,渲染顺序交由
getSortedSections()驱动,不要硬编码顺序; - 双栏:使用
grid-template-columns: 65% 35%、align-items: start、主栏border-right分隔,侧栏元素使用-sm变体与小字号类; - 打印:条目必须
break-inside: avoid,标题必须break-after: avoid+orphans/widows: 3,并在@media print中补充!important强化与标题-首条目同页规则; - 配置:新增的视觉自由度(如间距档位、字体选择)应接入
TemplateSettings与settingsToCssVars(),使预览与 PDF 两条路径同时生效。
结语
resume-template-design-spec.md以不足 70 行的篇幅浓缩了瑞士国际主义风格简历的全部设计约束,而 apps/frontend/components/resume/styles/_base.module.css、_tokens.css、swiss-single.module.css、swiss-two-column.module.css 四份样式文件与 resume-single-column.tsx、resume-two-column.tsx 两个组件则把每条规范翻译成了可运行、可测试、可被用户配置的工程实现。理解这份"设计宪法"与它的代码化身之间的关系,是继续为 Resume-Matcher 贡献新模板(如 Modern、LaTeX、Clean、Vivid 系列的扩展)的前提——所有模板共享同一套令牌系统与打印纪律,而瑞士双模板正是这套体系最经典的参照样本。
【免费下载链接】Resume-MatcherThe #1 AI Harness for Building Resumes, PDFs, Cover Letters & more, locally with 100+ LLMs support.项目地址: https://gitcode.com/GitHub_Trending/re/Resume-Matcher
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考