Typst 学生模板设计指南
每个功能的实现方法与参数详解。适用于课程作业、笔记、实习报告等学生场景。
目录
- 第一章:模板架构
- 第二章:字体系统
- 第三章:行距与段落
- 第四章:页面与元数据
- 第五章:封面
- 第六章:目录
- 第七章:页眉与页脚
- 第八章:多级标题
- 第九章:列表
- 第十章:代码块
- 第十一章:表格
- 第十二章:图片与题注
- 第十三章:公式
- 第十四章:Alert 系统
- 第十五章:交叉引用系统
- 第十六章:脚注
- 第十七章:完整模板代码
- 第十八章:最佳实践
- 附录:Typst vs Word
第一章:模板架构
核心思想
Typst 模板的本质是一个 函数,它接受参数、设置全局样式、返回正文内容。所有样式通过 set 和 show 规则控制。
// 最简模板结构
#let my-template(
title: none,
author: none,
body,
) = {
// 1. 全局样式设置
set text(font: "Noto Serif SC", size: 11pt)
set page(paper: "a4", numbering: "1")
set par(justify: true, leading: 0.8em)
// 2. 封面(可选)
if title != none {
align(center + horizon)[
#text(2em, weight: "bold")[#title]
#v(1em)
#author
]
pagebreak()
}
// 3. 正文
body
}使用方式
#show: my-template.with(
title: "我的文档",
author: "张三",
)
= 第一章
这里是正文内容。参数设计原则
- 必填参数放最后:
body是必填的,放在参数列表末尾 - 可选参数给默认值:
title: none表示可选 - 复杂参数用字典:字体、边距等用字典传入
- 布尔参数用命名参数:
show-cover: true比true更清晰
第二章:字体系统
中英文混排
Typst 的字体设置支持回退机制,当主字体缺少某个字符时自动使用备选字体:
// 字体字典:按用途分类
#let fonts = (
serif: "Source Han Serif SC", // 中文正文(宋体)
sans: "Source Han Sans SC", // 中文标题(黑体)
mono: "JetBrains Mono", // 等宽字体(代码)
math: "New Computer Modern Math", // 数学公式
math-cjk: "Source Han Serif SC", // 公式中的中文
)
// 设置全局字体
set text(font: (fonts.serif, "Times New Roman"), size: 11pt)参数说明:
font接受数组时,第一个匹配的字体优先使用("Source Han Serif SC", "Times New Roman")表示:中文用思源宋体,英文用 Times New Roman
不同元素的字体
// 正文:宋体
set text(font: (fonts.serif, "Times New Roman"))
// 标题:黑体
show heading: set text(font: (fonts.sans, "Arial"))
// 代码:等宽字体
show raw: set text(font: fonts.mono)
// 强调:可以换字体
show emph: set text(font: (fonts.serif, "Times New Roman"), weight: "bold")字体大小层级
// 建立清晰的大小层级
set text(size: 11pt) // 正文 11pt
show heading.where(level: 1): set text(size: 1.6em) // 一级标题
show heading.where(level: 2): set text(size: 1.3em) // 二级标题
show heading.where(level: 3): set text(size: 1.1em) // 三级标题检查可用字体
typst fonts第三章:行距与段落
行距(leading)
行距是 同一段落内 行与行之间的距离:
// leading: 行距
set par(leading: 0.8em) // 行距 = 0.8 × 字号推荐值:
| 值 | 效果 | 适用场景 |
|---|---|---|
0.6em |
紧凑 | 代码、表格 |
0.8em |
标准 | 正文(推荐) |
1.0em |
宽松 | 低年级阅读材料 |
段距(spacing)
段距是 段落与段落 之间的距离:
// spacing: 段距
set par(spacing: 1em) // 段距 = 1 × 字号首行缩进 vs 段间距
这是中文学术排版的核心决策,二选一:
// 方案 A:传统首行缩进(2 字符)
set par(first-line-indent: 2em)
// 方案 B:现代段间距(无缩进)
set par(first-line-indent: 0pt, spacing: 1.2em)用参数让用户选择:
#let template(
indent: "spacing", // "spacing" 或 "traditional"
body,
) = {
set par(
first-line-indent: if indent == "traditional" { 2em } else { 0pt },
spacing: if indent == "spacing" { 1.2em } else { 0.8em },
)
body
}两端对齐
// justify: 两端对齐(中文推荐开启)
set par(justify: true)第四章:页面与元数据
页面设置
set page(
paper: "a4", // 纸张大小
margin: ( // 边距
top: 3cm,
bottom: 2.5cm,
left: 2.5cm,
right: 2.5cm,
),
numbering: "1", // 页码格式
number-align: center, // 页码位置
)页码格式选项:
| 格式 | 输出 |
|---|---|
"1" |
1, 2, 3, ... |
"I" |
I, II, III, ...(罗马数字,适合前言) |
"一" |
一, 二, 三, ...(中文数字) |
元数据参数
完整的元数据参数设计:
#let template(
// === 必填 ===
body, // 正文内容
// === 基本信息 ===
title: none, // 文档标题
subtitle: none, // 副标题(可选)
author: none, // 作者姓名
student-id: none, // 学号
date: datetime.today(), // 日期
// === 课程信息 ===
course: none, // 课程名称
instructor: none, // 教师姓名
semester: none, // 学期(如 "2025 春")
// === 作业专用 ===
assignment-num: none, // 作业编号
deadline: none, // 截止日期
// === 控制开关 ===
show-cover: false, // 是否显示封面
show-outline: false, // 是否显示目录
outline-depth: 2, // 目录深度
// === 排版选项 ===
indent: "spacing", // 缩进方式:"spacing" 或 "traditional"
font-size: 11pt, // 正文字号
) = { ... }元数据访问
在模板内部通过参数名直接访问:
#let template(title: none, author: none, body) = {
// 在页眉中使用元数据
set page(
header: {
if title != none {
align(center)[#text(0.8em)[#title]]
}
}
)
// 在封面中使用元数据
if title != none {
align(center + horizon)[
#text(2em, weight: "bold")[#title]
#v(1em)
#author
]
pagebreak()
}
body
}第五章:封面
基础封面
#let cover(title, author, course, semester, date) = {
// 页码不计入封面
counter(page).update(0)
align(center + horizon)[
#text(2em, weight: "bold")[#title]
#v(1.5em)
#text(1.2em)[#course]
#v(1em)
#text(1em)[
#author \
#semester \
#date
]
]
pagebreak()
}关键函数说明:
| 函数 | 作用 |
|---|---|
counter(page).update(0) |
重置页码,封面不计入页码 |
align(center + horizon) |
水平居中 + 垂直居中(Typst 独有优势) |
v(1.5em) |
垂直间距,em 相对于当前字号 |
信息更丰富的封面
#let cover(
title: none,
subtitle: none,
author: none,
student-id: none,
course: none,
instructor: none,
semester: none,
date: none,
) = {
counter(page).update(0)
align(center + horizon)[
// 标题
#text(2.2em, weight: "bold")[#title]
#if subtitle != none [
#v(0.5em)
#text(1.4em)[#subtitle]
]
#v(3em)
// 信息表格
#set text(size: 1.1em)
#table(
columns: 2,
stroke: none,
align: (right, left),
inset: (x: 0pt, y: 6pt),
[课程], [*#course*],
[教师], [*#instructor*],
[学期], [*#semester*],
[姓名], [*#author*],
[学号], [*#student-id*],
[日期], [*#date*],
)
]
pagebreak()
}注意:table 的 align 参数接受数组,(right, left) 表示第一列右对齐、第二列左对齐。
第六章:目录
基础目录
#let outline(depth: 2) = {
// 标题居中
show heading.where(level: 1): align(center)
// 目录内容
[ #outline(title: [目录], depth: depth) ]
pagebreak()
}自定义目录样式
#let custom-outline(depth: 2) = {
// 目录标题样式
show outline.title: set text(size: 1.4em, weight: "bold")
// 目录项样式
show outline.entry.where(level: 1): it => {
set text(weight: "bold")
it
}
// 缩进
show outline.entry: set block(indent: 1.5em)
outline(title: [目录], depth: depth)
pagebreak()
}目录深度
outline(depth: 1) // 只显示一级标题
outline(depth: 2) // 显示到二级标题(推荐)
outline(depth: 3) // 显示到三级标题第七章:页眉与页脚
基础页眉
set page(
header: {
set text(0.8em, fill: luma(120))
grid(
columns: (1fr, auto, 1fr),
align(left, [课程名称]),
align(center, [文档标题]),
align(right, [作者]),
)
v(0.3em)
line(length: 100%, stroke: 0.5pt + luma(150))
},
)函数说明:
| 函数 | 作用 |
|---|---|
grid(columns: (1fr, auto, 1fr)) |
三列布局,1fr 表示弹性宽度 |
line(length: 100%) |
水平线,100% 表示占满宽度 |
首页隐藏页眉
set page(
header: context {
// context 关键字允许访问文档状态
let page-num = counter(page).get().first()
if page-num > 1 {
// 从第二页开始显示页眉
[页眉内容]
}
},
)关键概念:context 允许在显示规则中访问文档状态(如页码、计数器)。
页脚
set page(
footer: {
align(center)[
#counter(page).display("1 / 1", both: true)
]
},
)页码格式:
"1":当前页码"1 / 1":需要both: true才能显示总页数
奇偶页不同页眉
set page(
header: context {
let page-num = counter(page).get().first()
if calc.odd(page-num) {
// 奇数页:页眉在右侧
align(right)[奇数页页眉]
} else {
// 偶数页:页眉在左侧
align(left)[偶数页页眉]
}
},
)第八章:多级标题
标题样式
// 一级标题:大号、加粗、有下边距
show heading.where(level: 1): it => {
set text(size: 1.6em, weight: "bold")
it
v(0.5em)
}
// 二级标题:中号、加粗
show heading.where(level: 2): it => {
set text(size: 1.3em, weight: "bold")
it
v(0.3em)
}
// 三级标题:小号、加粗
show heading.where(level: 3): it => {
set text(size: 1.1em, weight: "bold")
it
}标题编号
// 阿拉伯数字:1, 1.1, 1.1.1
set heading(numbering: "1.1.1")
// 中文数字:一、,(一),1.
set heading(numbering: "一、(一)1.")
// 混合格式
set heading(numbering: "第 1 章 1.1 1.1.1")使用 numbly 包自定义:
#import "@preview/numbly:0.1.0": numbly
// {1} 表示一级标题的编号,{2} 表示二级,以此类推
set heading(numbering: numbly(
"{1:第 [1] 章} ",
"{2:[1].[2] ",
"{3:[1].[2].[3] ",
))无编号标题
// 用 = 创建编号标题
= 有编号的标题
// 用 = 创建无编号标题(在 heading 后加 *)
= 无编号的标题*标题锚点与引用
= 引言 <intro>
如 @intro 所述,本文将讨论...关键优势:<label> 标签可以附加在任何元素上,通过 @label 引用时自动获取编号。
第九章:列表
无序列表
- 项目一
- 项目二
- 子项目
- 子项目
- 项目三样式设置:
set list(
indent: 1.5em, // 整体缩进
body-indent: 0.5em, // 文字与标记的距离
marker: ([•], [‣], [–]), // 不同层级的标记
)有序列表
+ 第一步
+ 第二步
+ 子步骤
+ 第三步样式设置:
set enum(
indent: 1.5em,
body-indent: 0.5em,
numbering: "1.", // 编号格式
// numbering: "(1)", // 带括号
// numbering: "a.", // 字母
// numbering: "I.", // 罗马数字
)任务列表(复选框)
// Typst 原生支持任务列表
- [x] 已完成的任务
- [ ] 未完成的任务
- [ ] 另一个未完成的任务这是 Word 做不到的,非常适合作业清单、待办事项。
术语列表
/ 术语一: 定义内容
/ 术语二: 定义内容样式设置:
set terms(indent: 1.5em, separator: [: ])第十章:代码块
行内代码
使用 `print()` 函数输出内容。样式设置:
show raw.where(block: false): box.with(
fill: luma(240),
inset: (x: 3pt, y: 0pt),
outset: (y: 3pt),
radius: 2pt,
)代码块
```python
def hello():
print("Hello, World!")
```样式设置:
show raw.where(block: true): block.with(
width: 100%,
fill: luma(245),
inset: (x: 10pt, y: 8pt),
radius: 4pt,
)带行号的代码块
#import "@preview/codelst:2.0.0": sourcecode
#sourcecode(numbers: "left")[
```python
def hello():
print("Hello, World!")]
**参数说明**:
| 值 | 效果 |
|---|---|
| `numbers: "left"` | 行号在左侧 |
| `numbers: "right"` | 行号在右侧 |
| `numbers: none` | 无行号 |
### 代码块标题
```typst
#figure(
sourcecode(numbers: "left")[
```python
def hello():
print("Hello, World!")
```
],
caption: [示例代码],
) <code:hello>
第十一章:表格
简单表格
#set table(
stroke: 0.5pt,
align: center + horizon,
inset: (x: 8pt, y: 6pt),
)
#figure(
table(
columns: 3,
[姓名], [学号], [成绩],
[张三], [001], [95],
[李四], [002], [88],
),
caption: [成绩表],
) <tab:score>参数说明:
| 参数 | 说明 |
|---|---|
columns: 3 |
3 列(等宽) |
columns: (1fr, 2fr, 1fr) |
指定每列宽度比例 |
stroke: 0.5pt |
边框线粗细 |
align: center + horizon |
水平居中 + 垂直居中 |
inset: (x: 8pt, y: 6pt) |
单元格内边距 |
三线表(学术必备)
#let three-line-table(columns: (), header: (), ..body) = {
table(
columns: columns,
stroke: none,
// 顶线:粗
table.hline(stroke: 1.5pt),
// 表头分隔线:细
table.hline(stroke: 0.75pt, y: 1),
// 表头内容
..header,
// 表体内容
..body,
// 底线:粗
table.hline(stroke: 1.5pt),
)
}
// 使用示例
#figure(
three-line-table(
columns: (1fr, 1fr, 1fr),
header: ([变量], [类型], [说明]),
[x], [int], [输入],
[y], [int], [输出],
),
caption: [三线表示例],
) <tab:three-line>关键点:
| 函数 | 作用 |
|---|---|
table.hline(stroke: 1.5pt) |
粗线(顶线、底线) |
table.hline(stroke: 0.75pt, y: 1) |
细线(表头下方),y: 1 表示在第 1 行之后 |
stroke: none |
先去掉默认边框,再手动添加 |
跨列表格
#table(
columns: 3,
stroke: 0.5pt,
// 跨列:colspan
table.cell(colspan: 3, align: center)[合并的单元格],
[A], [B], [C],
// 跨行:rowspan
table.cell(rowspan: 2)[合并], [1], [2],
[], [3], [4],
)表格对齐
#table(
columns: 3,
stroke: 0.5pt,
// 每列单独设置对齐
align: (left, center, right),
[左对齐], [居中], [右对齐],
)第十二章:图片与题注
基础图片
#figure(
image("figure.png", width: 80%),
caption: [实验结果],
) <fig:result>参数说明:
| 参数 | 说明 |
|---|---|
width: 80% |
宽度占容器的 80% |
width: 300pt |
固定宽度 |
height: 200pt |
固定高度(与 width 二选一) |
fit: "contain" |
保持比例(默认) |
图片引用
如 @fig:result 所示,实验结果表明...自动编号:图片编号由 figure 自动管理,无需手动设置。
图片并排
#figure(
grid(
columns: 2,
gutter: 1em,
image("fig1.png", width: 100%),
image("fig2.png", width: 100%),
),
caption: [并排图片],
) <fig:side-by-side>题注位置
// 表格题注在上方(学术规范)
show figure.where(kind: table): set figure.caption(position: top)
// 图片题注在下方(默认)
show figure.where(kind: image): set figure.caption(position: bottom)第十三章:公式
行内公式
质能方程 $E = m c^2$ 是物理学的基础。块级公式
$ sum_(i=1)^n i = (n(n+1)) / 2 $ <eq:sum>公式编号
// 全局设置
set math.equation(numbering: "(1)")
// 或者在 show 规则中设置
show math.equation.where(block: true): set math.equation(numbering: "(1)")公式引用
如 @eq:sum 所示,等差数列求和公式为...多行公式对齐
$
f(x) &= x^2 + 2x + 1 \
&= (x + 1)^2
$关键符号:
| 符号 | 作用 |
|---|---|
& |
对齐点 |
\\ |
换行 |
= |
对齐在等号处 |
第十四章:Alert 系统
设计思路
Alert 是类似 GitHub Markdown Alerts 的设计,用于标注重要信息。
基础 Alert 函数
#let alert(
title: none, // 标题(可选)
icon: "💡", // 图标
color: rgb("#0066cc"), // 主题色
fill: rgb("#e6f3ff"), // 背景色
body, // 内容
) = {
block(
width: 100%,
fill: fill,
stroke: color,
radius: 6pt,
inset: 12pt,
[
#if title != none [
#text(weight: "bold", fill: color)[#icon #title]
#v(4pt)
]
#body
],
)
}参数详解:
| 参数 | 说明 |
|---|---|
block(width: 100%) |
占满容器宽度 |
fill |
背景填充色 |
stroke |
边框颜色 |
radius |
圆角半径 |
inset |
内边距(内容与边框的距离) |
预定义 Alert 类型
// Note:蓝色,普通笔记
#let note(title: none, body) = {
alert(
title: title,
icon: "📝",
color: rgb("#0066cc"),
fill: rgb("#e6f3ff"),
body,
)
}
// Tip:绿色,建议
#let tip(title: none, body) = {
alert(
title: title,
icon: "💡",
color: rgb("#007a3d"),
fill: rgb("#e6f9e6"),
body,
)
}
// Warning:黄色,警告
#let warning(title: none, body) = {
alert(
title: title,
icon: "⚠️",
color: rgb("#856404"),
fill: rgb("#fff3cd"),
body,
)
}
// Important:紫色,重要信息
#let important(title: none, body) = {
alert(
title: title,
icon: "❗",
color: rgb("#6f42c1"),
fill: rgb("#f3e8ff"),
body,
)
}
// Caution:红色,危险操作
#let caution(title: none, body) = {
alert(
title: title,
icon: "🚨",
color: rgb("#dc3545"),
fill: rgb("#ffe6e6"),
body,
)
}使用示例
#note[这是普通笔记内容]
#tip(title: "建议")[优先使用方案 A]
#warning(title: "注意")[此操作不可逆]
#important(title: "重要")[请仔细阅读]
#caution(title: "警告")[删除前请备份]自定义 Alert 样式
// 左边框样式(替代全边框)
#let alert-left(title: none, icon: "💡", color: rgb("#0066cc"), body) = {
block(
width: 100%,
fill: color.lighten(90%),
radius: (left: 4pt, right: 0pt),
inset: (left: 12pt, right: 8pt, y: 10pt),
stroke: (left: 4pt + color, rest: none),
[
#if title != none [
#text(weight: "bold", fill: color)[#icon #title]
#v(4pt)
]
#body
],
)
}第十五章:交叉引用系统
标签(Label)
// 为任何元素添加标签
= 引言 <intro>
$ E = m c^2 $ <eq:einstein>
#figure(image("fig.png"), caption: [图]) <fig:example>
#table(columns: 2, [A], [B]) <tab:example>引用(Ref)
// 引用时自动获取编号
如 @intro 所述...
公式 @eq:einstein 表明...
如 @fig:example 所示...
见 @tab:example。自定义引用格式
// 修改引用样式
show ref: it => {
let target = it.target
// 根据引用类型添加前缀
if it.element.func() == heading {
text(fill: blue)[(第 #it 页)]
} else if it.element.func() == figure {
text(fill: blue)[图 #it]
} else {
it
}
}页码引用
// 引用页码
第 @page(ref) 页第十六章:脚注
基础脚注
这是一个脚注示例。#footnote[这是脚注内容。]脚注样式
// 修改脚注标记样式
show footnote: set text(size: 0.8em)
// 修改脚注内容样式
show footnote.entry: set text(size: 0.9em)手动脚注标记
// 自定义脚注标记
#footnote(numbering: "*")[特殊脚注]第十七章:完整模板代码
以下是整合所有功能的完整模板:
// ============================================================
// student-template.typ - 学生模板
// ============================================================
// 字体配置
#let fonts = (
serif: "Source Han Serif SC",
sans: "Source Han Sans SC",
mono: "JetBrains Mono",
math: "New Computer Modern Math",
math-cjk: "Source Han Serif SC",
)
// Alert 函数
#let alert(title: none, icon: "💡", color: rgb("#0066cc"), fill: rgb("#e6f3ff"), body) = {
block(
width: 100%,
fill: fill,
stroke: color,
radius: 6pt,
inset: 12pt,
[
#if title != none [
#text(weight: "bold", fill: color)[#icon #title]
#v(4pt)
]
#body
],
)
}
// 预定义 Alert 类型
#let note(title: none, body) = alert(title: title, icon: "📝", color: rgb("#0066cc"), fill: rgb("#e6f3ff"), body)
#let tip(title: none, body) = alert(title: title, icon: "💡", color: rgb("#007a3d"), fill: rgb("#e6f9e6"), body)
#let warning(title: none, body) = alert(title: title, icon: "⚠️", color: rgb("#856404"), fill: rgb("#fff3cd"), body)
// 三线表
#let three-line-table(columns: (), header: (), ..body) = {
table(
columns: columns,
stroke: none,
table.hline(stroke: 1.5pt),
table.hline(stroke: 0.75pt, y: 1),
..header,
..body,
table.hline(stroke: 1.5pt),
)
}
// 封面
#let cover(
title: none,
subtitle: none,
author: none,
student-id: none,
course: none,
instructor: none,
semester: none,
date: none,
) = {
counter(page).update(0)
align(center + horizon)[
#text(2.2em, weight: "bold")[#title]
#if subtitle != none [
#v(0.5em)
#text(1.4em)[#subtitle]
]
#v(3em)
#set text(size: 1.1em)
#table(
columns: 2,
stroke: none,
align: (right, left),
inset: (x: 0pt, y: 6pt),
[课程], [*#course*],
[教师], [*#instructor*],
[学期], [*#semester*],
[姓名], [*#author*],
[学号], [*#student-id*],
[日期], [*#date*],
)
]
pagebreak()
}
// 目录
#let outline-page(depth: 2) = {
show heading.where(level: 1): align(center)
[ #outline(title: [目录], depth: depth) ]
pagebreak()
}
// 主模板函数
#let student-template(
// 基本信息
title: none,
subtitle: none,
author: none,
student-id: none,
date: datetime.today(),
// 课程信息
course: none,
instructor: none,
semester: none,
// 作业专用
assignment-num: none,
deadline: none,
// 控制开关
show-cover: false,
show-outline: false,
outline-depth: 2,
// 排版选项
indent: "spacing",
font-size: 11pt,
body,
) = {
// === 全局样式 ===
set text(font: (fonts.serif, "Times New Roman"), size: font-size)
set page(
paper: "a4",
margin: (top: 3cm, bottom: 2.5cm, left: 2.5cm, right: 2.5cm),
numbering: "1",
number-align: center,
header: context if counter(page).get().first() > 1 {
set text(0.8em, fill: luma(120))
grid(
columns: (1fr, auto, 1fr),
align(left, [#course]),
align(center, [#title]),
align(right, [#author]),
)
v(0.3em)
line(length: 100%, stroke: 0.5pt + luma(150))
},
)
set par(
justify: true,
leading: 0.8em,
spacing: 0.8em,
first-line-indent: if indent == "traditional" { 2em } else { 0pt },
)
// === 标题样式 ===
show heading.where(level: 1): it => { set text(size: 1.6em, weight: "bold"); it; v(0.5em) }
show heading.where(level: 2): it => { set text(size: 1.3em, weight: "bold"); it; v(0.3em) }
show heading.where(level: 3): it => { set text(size: 1.1em, weight: "bold"); it }
set heading(numbering: "1.1.1")
// === 列表样式 ===
set list(indent: 1.5em, body-indent: 0.5em)
set enum(indent: 1.5em, body-indent: 0.5em)
// === 代码块样式 ===
show raw.where(block: false): box.with(fill: luma(240), inset: (x: 3pt, y: 0pt), outset: (y: 3pt), radius: 2pt)
show raw.where(block: true): block.with(width: 100%, fill: luma(245), inset: (x: 10pt, y: 8pt), radius: 4pt)
// === 表格样式 ===
show table: set table(stroke: 0.5pt, align: center + horizon, inset: (x: 8pt, y: 6pt))
// === 图片题注 ===
show figure.where(kind: table): set figure.caption(position: top)
// === 公式编号 ===
set math.equation(numbering: "(1)")
// === 封面 ===
if show-cover {
cover(
title: title,
subtitle: subtitle,
author: author,
student-id: student-id,
course: course,
instructor: instructor,
semester: semester,
date: date,
)
}
// === 目录 ===
if show-outline {
outline-page(depth: outline-depth)
}
// === 页码重置 ===
counter(page).update(1)
// === 正文 ===
body
}第十八章:最佳实践
1. 参数命名
// 好:语义清晰
#let template(
show-cover: false,
indent: "spacing",
font-size: 11pt,
)
// 差:含义模糊
#let template(
cover: false,
mode: "a",
size: 11,
)2. 默认值设计
// 所有参数都应该有合理的默认值
#let template(
title: none, // 可选:不显示标题
author: none, // 可选:不显示作者
font-size: 11pt, // 有默认值
indent: "spacing", // 有默认值
body, // 必填:无默认值
)3. 函数文档
/// 创建学生文档模板。
/// - title (string): 文档标题。
/// - author (string): 作者姓名。
/// - body (content): 正文内容。
/// -> content
#let template(title: none, author: none, body) = { ... }4. 避免全局状态
// 好:通过参数传递
#let template(font-size: 11pt, body) = {
set text(size: font-size)
body
}
// 差:直接修改全局状态
#let template(body) = {
set text(size: 11pt) // 硬编码
body
}5. 组件化设计
// 把复杂组件提取为独立函数
#let definition(title: none, body) = {
block(
width: 100%,
fill: rgb("#f0f8ff"),
stroke: rgb("#4682b4"),
radius: 4pt,
inset: 10pt,
[
#if title != none [
#text(weight: "bold", fill: rgb("#4682b4"))[定义:#title]
#v(4pt)
]
#body
],
)
}6. 测试模板
# 编译模板
typst compile student-template.typ student-template.pdf
# 清理编译缓存
typst clean
# 查看可用字体
typst fonts附录:Typst vs Word
Typst 的优势
- 确定性输出:同样的源码永远得到同样的 PDF
- 版本控制友好:纯文本,适合 Git
- 自动交叉引用:
@label自动更新编号 - 函数化模板:一个
show规则搞定全文样式 - 布局原语:
grid、stack、columns精确控制 - 原生数学公式:不需要插件
- 代码高亮:原生支持
- 编译速度快:比 LaTeX 快得多
Word 的优势
- 所见即所得:适合非技术用户
- 协作编辑:多人实时编辑
- 插件生态:丰富的插件支持
- 学习成本低:大多数人已经会用
选择建议
- 技术文档、学术论文、笔记:选 Typst
- 商务文档、协作编辑:选 Word
- 需要精确排版:选 Typst
- 需要快速修改:看情况
总结
本文档涵盖了 Typst 学生模板的所有设计要点:
- 模板架构:函数化设计,参数清晰
- 字体系统:中英文混排,层级分明
- 行距与段落:行距、段距、首行缩进
- 页面与元数据:页面设置、参数设计
- 封面:简洁美观,信息完整
- 目录:自动生成,支持深度控制
- 页眉页脚:灵活配置,首页隐藏
- 多级标题:样式统一,自动编号
- 列表:有序、无序、任务列表
- 代码块:语法高亮,行号支持
- 表格:简单表格、三线表
- 图片与题注:自动编号,交叉引用
- 公式:自动编号,多行对齐
- Alert 系统:多种类型,样式丰富
- 交叉引用:标签系统,自动更新
- 脚注:灵活配置
掌握这些设计要点,你就能创建一个功能完整、样式美观的 Typst 学生模板。
本站内容除特别声明外,均遵循 CC BY-NC-SA 4.0 协议