Typst 怎么写中文:字体、字号、缩进与标题编号
在 Typst 里排中文:lang 和 region 的作用,中西文字体搭配与 covers 参数,五号、小四等字号的写法,首行缩进、行距和段间距,中英文间距与标点挤压,中文粗体斜体与 cuti 伪粗体,"第一章""一、"式标题编号,以及 JointTex 编辑页面和服务器上各有哪些字体。
最后核对:2026-10-24Typst 不需要像 LaTeX 那样选编译引擎、加载 ctex:源文件里直接写中文就能编译。但它默认按英文习惯排版,中文文档开头要自己写几条 set 规则:语言、字体、段落缩进。本文从最小可用的写法开始,逐项讲清楚每条规则管什么,以及学校格式要求里的字号、行距、标题编号怎么写。
最简单的中文文档怎么写
// title: Typst 中文文档
// 1. 语言和地区:lang 决定"图""表""目录""参考文献"等名称,并让 Typst 按中文规则处理标点;
// region 决定标点的样式(cn 是简体中文的规范,tw、hk 用居中的标点)
// 2. 字体列表按顺序找字:每个字符取第一个含有它的字体。
// covers: "latin-in-cjk" 让西文字体只管拉丁字母,引号、破折号、省略号交给中文字体
#set text(
font: ((name: "Libertinus Serif", covers: "latin-in-cjk"), "Noto Serif CJK SC"),
lang: "zh",
region: "cn",
size: 12pt, // 小四号
)
// 3. 段落:两端对齐,每段(包括标题后的第一段)首行缩进两个字
#set par(justify: true, first-line-indent: (amount: 2em, all: true))
= 中文段落
这是一个最简单的中文文档。标题后面的第一段也缩进了两个字,这是 all: true 的作用;不写它时,Typst 按西文习惯不缩进标题后的第一段。
中文和 English 或数字 2026 之间的空白由 Typst 自动加上,源文件里写成中文English2026也是一样的效果。
= 标点
引号用“中文引号”,破折号——和省略号……都来自中文字体,所以是连在一起的一整条。相邻的标点会自动挤压,比如“(括号)”、句号后面的引号。
= 换行要注意
源文件里两个汉字之间的换行
会变成一个空格(看上一句“换行”后面)。所以一段话最好写在一行里,靠编辑器自动折行。
开头几条规则的作用:
lang: "zh":文档的语言。Typst 据此把"Figure""Table""Contents""Bibliography"换成"图""表""目录""参考文献",并按中文的规则处理标点。region: "cn":地区。它决定标点的样式:cn是简体中文的写法;写tw时,句号、逗号排在字的正中,"目录"也变成"目錄"。font:字体列表,下一节详细讲。first-line-indent: (amount: 2em, all: true):每段首行缩进两个字。2em是两个当前字号的宽度,字号变了缩进也跟着变。
Typst 的项目在 JointTex 里边写边编译,不需要按编译按钮;在 PDF 上双击,或按住 Cmd/Ctrl 点击,可以跳到对应的源码,反过来也可以从光标跳到 PDF。
中文字体和西文字体怎么搭配
font 可以是一个字体名,也可以是一个列表。Typst 对每个字符按列表顺序找字体,用第一个含有这个字符的。所以通常把西文字体写在前面,中文字体写在后面:英文字母和数字用西文字体,汉字用中文字体。
问题出在两种字体都有的字符上:中文引号“”、破折号——、省略号……、间隔号·。西文字体在前时,它们会取自西文字体,引号变窄,破折号断成两截,省略号沉到底部。covers: "latin-in-cjk" 解决这个问题,它让西文字体只负责"应该用西文字形"的字符,其余的交给后面的中文字体:
// 引号、破折号来自 Libertinus Serif:引号窄,——断开
#set text(font: ("Libertinus Serif", "Noto Serif CJK SC"))
// 引号、破折号来自 Noto Serif CJK SC:全角引号,——连成一条
#set text(font: ((name: "Libertinus Serif", covers: "latin-in-cjk"), "Noto Serif CJK SC"))
反过来把中文字体写在第一位也能编译,但中文字体自带的拉丁字母会取代西文字体,英文和数字的样子就变了。
还有一点:一定要写出中文字体的名字。只写 font: "Libertinus Serif" 时,汉字由 Typst 自己找一个含有汉字的字体代替,在 JointTex 的编辑页面里找到的是 Noto Serif CJK JP(日文字形),有些汉字的写法和简体中文规范不同。
公式里也一样:数学公式用自己的字体,不读正文的 font 设置,所以 $ v = "速度" $ 里的汉字同样会用 Noto Serif CJK JP。要让公式里的汉字也用简体字形,单独给公式设一条规则:
#show math.equation: set text(font: ("New Computer Modern Math", "Noto Serif CJK SC"))
JointTex 里能用哪些字体
Typst 项目在两个地方编译,可用的字体不完全一样:
- 编辑页面(浏览器里随输入实时编译):Typst 自带的 Libertinus Serif、New Computer Modern、New Computer Modern Math、DejaVu Sans Mono,加上 Noto Serif CJK(思源宋体)的 SC、TC、JP、KR、HK 五个版本,各有 Regular 和 Bold 两个字重。本页示例只用这些字体。
- 服务器:除了上面的字体,还有 Noto Sans CJK(思源黑体)等 Noto CJK 字体。项目里的
fonts/文件夹也会被搜索,自己上传的字体放在这里。服务器用的 Typst 版本和编辑页面相同,都是 0.15.1。
文档要的字体当前环境没有时,Typst 不报错,只给出一条警告,然后用别的字体代替:
warning: unknown font family: simsun
注意警告里的字体名是小写的。所以在编辑页面里用了黑体或上传的字体,预览看到的会是代替的字体;下载的 PDF 由服务器编译,用的才是真正的字体。宋体、黑体等 Windows 字体是商业字体,上传前请确认授权。
字号怎么设置:五号、小四
Typst 的字号用 pt 写,默认是 11pt。中文的号数和 pt 的对应关系(与 ctex、Word 一致):
| 号数 | 初号 | 小初 | 一号 | 小一 | 二号 | 小二 | 三号 | 小三 | 四号 | 小四 | 五号 | 小五 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| pt | 42 | 36 | 26 | 24 | 22 | 18 | 16 | 15 | 14 | 12 | 10.5 | 9 |
可以直接写 size: 12pt,也可以自己定义一个字典,用汉字取值(Typst 的变量名可以是汉字):
#let 字号 = (三号: 16pt, 四号: 14pt, 小四: 12pt, 五号: 10.5pt)
#set text(size: 字号.小四)
更省事的是 Typst Universe 上的 pointless-size 包:zh(5) 是五号,zh(-4) 是小四(负数表示"小"),也可以写 zh("小四")。下面的示例用它设置正文和标题的字号,同时演示行距和粗体:
// title: Typst 字号、行距与粗体
// pointless-size 提供中文字号:zh(5) 是五号,zh(-4) 是小四;cuti 提供伪粗体
#import "@preview/pointless-size:0.1.3": zh
#import "@preview/cuti:0.4.0": fakebold
#set page(paper: "a4", margin: 2.5cm)
#set text(
font: ((name: "Libertinus Serif", covers: "latin-in-cjk"), "Noto Serif CJK SC"),
lang: "zh",
region: "cn",
size: zh(-4), // 小四号,即 12pt
// 行的上下边缘固定为 0.8em 和 -0.2em,每行高度正好是一个字号,
// 这样"相邻两行基线的距离 = 字号 + leading",容易按要求换算
top-edge: 0.8em,
bottom-edge: -0.2em,
)
// 要求"固定行距 20 磅":20pt - 12pt = 8pt
// spacing 是段与段之间的距离,写成和 leading 一样,段间就不再多空一行
#set par(
justify: true,
first-line-indent: (amount: 2em, all: true),
leading: 8pt,
spacing: 8pt,
)
// 标题用三号字;show 规则只改一级标题
#show heading.where(level: 1): set text(size: zh(3))
#show heading.where(level: 1): set align(center)
= 字号与行距
正文是小四号(12pt),相邻两行基线相距 20pt。这一段写得长一些,好让它占两行以上,可以看出行与行之间的距离。
这是第二段。它紧接着第一段,中间没有额外的空白,只靠首行缩进区分段落,这是中文论文常见的排法。
#text(size: zh(5))[这一句是五号字(10.5pt)。]#text(size: zh("小五"))[这一句是小五(9pt),字号也可以直接写汉字。]
= 粗体和强调
*星号之间是粗体*,Typst 用的是 Noto Serif CJK SC 自带的 Bold 字重。Typst 不会伪造粗体:如果字体没有粗体字重(比如只有一个字重的仿宋),加粗不会有任何效果。这时可以用 cuti 包:#fakebold[这一句是用描边模拟的粗体],可以和上面的真粗体比较。
_下划线之间是强调(emph)_:西文变成斜体(_italic_),汉字没有斜体字形,Typst 也不会把汉字倾斜,所以看上去不变。中文的强调一般用粗体。
Typst Universe 上的包在 JointTex 里可以直接 #import,版本号要写完整,例如 @preview/pointless-size:0.1.3。
行距和段落间距怎么调
Typst 的行距不是"几倍行距",而是两行之间的空白,由 par 的 leading 控制,默认 0.65em;段与段之间的距离由 spacing 控制,默认 1.2em。几点要注意:
- 默认一行的"高度"从基线算到字体的大写字母顶端(
text的top-edge默认"cap-height",bottom-edge默认"baseline"),换了字体,同样的leading得到的基线距离也会变。要按"固定行距 20 磅"这类要求设置,可以像示例那样写top-edge: 0.8em, bottom-edge: -0.2em,让每行的高度正好是一个字号,这时相邻两行基线的距离就是"字号 + leading":小四号要 20 磅行距,leading写20pt - 12pt = 8pt。 - 中文论文一般段与段之间不空行,只靠首行缩进区分段落。把
spacing设成和leading一样即可。 - 中文正文通常两端对齐,写
justify: true。
LaTeX 里对应的是 ctex 的 linespread 选项,见 LaTeX 中文排版。两者的算法不同,数值不能照搬。
标题后面的第一段为什么不缩进
Typst 默认按西文习惯,只缩进"前面也是段落"的段落,标题、图表、列表后面的第一段不缩进。只写 first-line-indent: 2em 时就是这样。中文要求每段都缩进,所以写成 first-line-indent: (amount: 2em, all: true)。这个写法是 Typst 0.13 加入的,更早的版本不支持。
中英文之间的空格和标点
- 中西文间距:
text的cjk-latin-spacing默认是auto,Typst 会在汉字和西文字母、数字之间自动加上间距。源文件里加不加空格,结果一样;写cjk-latin-spacing: none关掉它。 - 标点挤压:相邻的中文标点(比如"。」"或"、(")会自动挤掉半个字的空白,行首的开引号、开括号也会调整,不需要设置。
- 换行变成空格:源文件里两个汉字之间的换行会变成一个空格(Typst 按西文的规则处理换行)。最简单的办法是一段写在一行里,让编辑器自动折行;也可以用
cjk-unbreak包:#import "@preview/cjk-unbreak:0.2.3": remove-cjk-break-space,再写#show: remove-cjk-break-space。按它的说明,换行两侧有一边不是普通文字(例如加粗的部分)时,空格不会去掉。
中文的粗体和斜体
*粗体* 会选用字体的 Bold 字重。编辑页面里的 Noto Serif CJK 有 Bold,所以粗体正常。但 Typst 不会伪造粗体:字体只有一个字重时(例如 Windows 的宋体 SimSun),加粗没有任何效果,也没有警告。这时用 cuti 包,它用描边模拟粗体:#fakebold[...] 加粗一段文字,或者写 #show: show-cn-fakebold,让所有 *...* 里的汉字和中文标点都改用模拟粗体。
_强调_ 对西文是斜体;汉字没有斜体字形,Typst 也不会把汉字倾斜,所以中文看上去不变。中文的强调一般用粗体;想用楷体,要把楷体字体上传到项目的 fonts/ 文件夹,并且只有服务器编译时才能用上。
标题编号怎么改成"第一章"和"一、"
heading 的 numbering 除了 "1.1" 这样的模式,还可以写汉字数字:模式里的 一 表示汉字数字,第一章 就是"第" + 汉字数字 + "章"。各级用不同的格式时,numbering 写成一个函数,参数是各级的编号:
// title: Typst 中文标题编号
#set text(
font: ((name: "Libertinus Serif", covers: "latin-in-cjk"), "Noto Serif CJK SC"),
lang: "zh",
region: "cn",
)
#set par(justify: true, first-line-indent: (amount: 2em, all: true))
// numbering 可以是一个函数:参数是各级的编号,返回这一级标题显示的内容。
// 编号模式里的"一"表示汉字数字,"第一章"就是"第" + 汉字数字 + "章"
#set heading(numbering: (..nums) => {
let n = nums.pos()
if n.len() == 1 { numbering("第一章", ..n) } // 一级:第一章
else { numbering("1.1", ..n) } // 二、三级:1.1、1.1.1
})
// 引用标题时,Typst 默认在编号前加"小节"二字;改成 none 后只输出编号本身
#set heading(supplement: none)
// 一级标题居中、三号字(16pt)
#show heading.where(level: 1): set align(center)
#show heading.where(level: 1): set text(size: 16pt)
#outline()
= 绪论 <intro>
== 研究背景 <bg>
本节是第 @bg 节,编号由一级标题的序号和本级的序号组成。
=== 国内研究现状
三级标题的编号是 1.1.1。
== 本文结构
// 标签后面紧跟汉字时,@intro介绍 会被当成标签 <intro介绍>,所以改用 #ref(<intro>)
#ref(<intro>)介绍背景,#ref(<method>)介绍方法。
= 研究方法 <method>
二级标题的编号在新的一章重新从 1 开始:
== 数据来源
这一节的编号是 2.1。
几个细节:
numbering("一", 12)得到"十二",numbering("壹", 3)得到大写的"叁"。- 引用标题时,Typst 在中文文档里默认输出"小节 1.1"。
set heading(supplement: none)去掉"小节",自己在正文里写"第 @bg 节"。 @intro介绍会被读成标签<intro介绍>,报错error: label `<intro介绍>` does not exist in the document,因为汉字也可以是标签名的一部分。标签后面紧跟汉字时写成#ref(<intro>)介绍。- 目录
#outline()的标题也是一级标题,所以上面居中的规则也作用于"目录"二字。
另一种常见的"一、(一)1."格式这样写。Typst 在编号和标题之间固定留 0.3em 的空隙,"、"本身已经带空白,所以在编号后加 h(-0.3em) 抵消:
#set heading(numbering: (..nums) => {
let n = nums.pos()
if n.len() == 1 { numbering("一、", ..n) + h(-0.3em) }
else if n.len() == 2 { numbering("(一)", n.last()) + h(-0.3em) }
else { numbering("1.", n.last()) }
})
常见问题对照
| 现象 | 原因 | 解决 |
|---|---|---|
warning: unknown font family: ... | 当前环境没有这个字体 | 换成环境里有的字体,或把字体上传到项目的 fonts/ 文件夹(只有服务器编译能用) |
| 汉字字形不像简体中文 | 字体列表里没有中文字体(或在公式里),Typst 自己找到了日文字体 | 在 font 里写上 "Noto Serif CJK SC";公式用 show math.equation: set text(font: ...) |
label `<example.com>` does not exist in the document | 正文里的邮箱 [email protected] 被当成了引用 | 写成 zhang\@example.com |
| 中文引号很窄,破折号断开 | 这些字符取自西文字体 | 西文字体加 covers: "latin-in-cjk" |
| 标题后第一段不缩进 | 默认只缩进连续的段落 | first-line-indent: (amount: 2em, all: true) |
| 汉字之间多出空格 | 源文件里在这里换了行 | 一段写在一行,或用 cjk-unbreak |
| 加粗没有效果 | 字体没有粗体字重 | 用 cuti 包的 fakebold |
| 引用标题显示"小节 1.1" | 中文文档里标题的默认 supplement | set heading(supplement: none) |
Typst 的报错在 JointTex 里会在源码中标出,并列在"问题"标签页里。其他报错的含义见 Typst 常见报错,中文参考文献的写法见 Typst 参考文献。
