章首那个把段落第一个字母放大并沉进前几行的装饰字,英文叫 drop cap,法文叫 lettrine。在 LaTeX 里担此重任的,正是以这个词命名的宏包——Daniel Flipo 的 lettrine(TeX Live 2024 附带 v2.60,日期 2024-01-20)。这个装饰看似纯属外观问题,实现却精密得近乎执拗:lettrine 会真的排出一个四字母的基准串 EFTZ,量出它的高度,再用 xfp 的 \fpeval 算出缩放系数。实测中,目标高度 28.98666pt,实际得到的字母高 28.98679pt——偏差 0.00013pt。本页覆盖 \lettrine 的两个必需参数、lines=/lhang=/loversize=/findent= 等选项、底层的 \parshape 与 \llap,以及在列表、双栏和中日文里究竟会发生什么。
\lettrine 怎么用:两个参数,中间不留空格
在导言区写上 \usepackage{lettrine},然后用 \lettrine[选项]{T}{he rest} 开始这一段。 必需参数有两个。第一个 {T} 就是要沉下去的首字母本身;第二个 {he rest} 是紧随其后的文字,默认以小型大写字母排出。段落其余部分会自动绕到首字母右侧。{T} 与 {he rest} 之间绝不能有空格——把首词剩下的部分原样交给第二个参数才是正确写法。第二个参数留空也无妨(\lettrine{T}{} 只沉首字母,后续词以常规字体起排)。
\documentclass{article}
\usepackage{lettrine}
\usepackage{lmodern} % a fully scalable font — see below
\begin{document}
\lettrine{L}{orem} ipsum dolor sit amet, consectetur
adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua.
\end{document}这里潜伏着一个陷阱。lettrine 会把首字母放大到任意尺寸,因此需要一款任何尺寸都可用的字体。Computer Modern(CM)与 EC 字体默认只提供固定档位的字号,一旦请求的尺寸不在档位上,就会被替换成最接近的一档,首字母便填不满你要求的行数。稳妥的做法是加上 \usepackage{lmodern}(Latin Modern),或改用 Palatino、Times 这类 PostScript/OpenType 字体。若非留在 CM 不可,就载入 \usepackage{type1cm};用 EC 则载入 \usepackage{type1ec}。是否发生了替换,看日志便知——出现 LaTeX Font Warning: Font shape ... in size <31.53638> not available (Font) size <24.88> substituted 这样的行,就说明首字母缩水了。
内部到底做了什么:不是 \hangindent,而是 \parshape 加 \llap
lettrine 并不使用 \hangindent。 手工做首字下沉时常见的说法是「用 \hangindent 和 \hangafter 把前几行缩进,再往空出的地方放一个大字」,但 lettrine.sty 的实现不是这样。它先用 \sbox 把首字母装箱,再构造一个 \parshape——逐行给出(缩进量, 行长)的成对数值,用 \noindent 取消段首缩进,最后用 \llap 把装了首字母的盒子推向左边距。\hangindent 只能表达「前 n 行统一缩进多少」,而 \parshape 可以让每一行有不同的缩进。slope= 选项之所以能让正文左缘顺着 A 或 V 的斜边倾斜,正是靠这个结构。
弄清高度是怎么算出来的,lines= 的含义也会随之改变。lines=n 并不是「\baselineskip 的 n 倍」。 目标高度是 (n − 1) 行的 \baselineskip 加上后续文字所用字体(\LettrineTextFont,默认为 \scshape)的 x 高度。在 10pt 的 article 中实测:\baselineskip 为 12.0pt,\scshape 的 x 高 4.98666pt;lines=3 时日志给出的目标值是 28.98666pt,恰好等于 12 × 2 + 4.98666。实际得到的字母高 28.98679pt。这两行每次编译都会写进 .log,所以当首字母大小不对时,请先读这里:若发生了字体替换,目标值与实测值会相差很大。
% lettrine reports both numbers in the .log on every run:
% Package lettrine.sty Info: Targeted height = 28.98666pt
% (lettrine.sty) (for loversize=0, accent excluded),
% (lettrine.sty) Lettrine height = 28.98679pt (L);
%
% Read them when an initial comes out the wrong size:
% pdflatex doc.tex && grep -A3 "Targeted height" doc.log要紧的选项:lines=、lhang=、loversize=、findent=
外观通过方括号内以逗号分隔的选项来调节。 常用的有四个:lines= 决定首字母有多少行高,lhang= 决定它探入左边距多少,loversize= 决定在行高之外再放大多少,findent= 决定首字母与第一行文字之间的间隙。实务中最值得琢磨的是 lhang=:O、C 这类轮廓浑圆的字母略微探出边距(通常 0.1 到 0.2)后,视觉上的左对齐才显得齐整;左上角横杠外伸的 T 同理。而 H、N 这类左缘垂直的字母,保持 0 才对。这些数值都是相对于字母自身宽度或高度的比例,所以换字体后视觉关系依然成立。
| 选项 | 含义 | 默认值 |
|---|---|---|
lines | 首字母的高度:(n−1) 行 \baselineskip 加后续文字的 x 高度 | 2 |
lhang | 按字母宽度的比例探入左边距(0–1);对 O、C、T 有效 | 0 |
loversize | 相对目标高度的放大比例(−1 到 1);0.1 表示高 10 % | 0 |
lraise | 按自身高度的比例把首字母抬高 | 0 |
findent | 首字母与第一行文字之间的间隙 | 0pt |
nindent | 第二行及以后各行的缩进量 | 0.5em |
slope | 环绕正文左缘的斜度,用于 A、V 这类斜边字母 | 0pt |
depth | 首字母比常规再多沉几行 | 0 |
ante | 紧排在首字母之前的内容,如法语的开引号 guillemet | 无 |
image | 用图像作为首字母;需要 graphicx,可用 viewport= 裁切 | false |
refstring | 替换用于定高的基准字符串;当 EFTZ 不适合某种花体时使用 | EFTZ |
同样这些键也可以在载入宏包时给出,那时它们成为整份文档的默认值。写 \usepackage[lines=3]{lettrine},三行便成为默认;写在单个 \lettrine[...] 上的选项则只在该处覆盖默认值。若某个字母每次都要同样的设置,还可以用 \LettrineOptionsFor{O}{lhang=0.2} 登记按字母的默认值。这样「只让圆形字母探出去」就成了一次性的活儿,不必反复。
首字母的字体与颜色:\LettrineFontHook 怎么用
首字母的字体通过 \renewcommand 改写 \LettrineFontHook 来指定。 字号由行数自动算出,无需直接改动 \LettrineFont。钩子里放的是低层字体命令——例如写上 \fontfamily{ppl}\fontseries{bx}\fontshape{sl},就只让首字母变成 Palatino 的粗斜体。在 LuaLaTeX 或 XeLaTeX 下可以改走 fontspec:\renewcommand{\LettrineFontHook}{\fontspec{LinLibertine_I.otf}} 即可切换到 Linux Libertine 的装饰性首字母。后续文字(第二个参数)的字体由另一个钩子 \LettrineTextFont 掌管,默认是 \scshape。若不想要小型大写,就写 \renewcommand{\LettrineTextFont}{\rmfamily}。
改颜色时要留意括号的类型。要灰色,写法是 \renewcommand{\LettrineFontHook}{\color[gray]{0.5}}。 常见的 \color{gray}{0.5} 不会报错,却给出错误的结果:真排一遍就会发现,\color{gray} 选中了名为 gray 的颜色,剩下的 {0.5} 被当作文字排了出来,于是首字母左下角印出一个小小的「0.5」。钩子里的内容是直接在 \sbox 中执行的,写下会产生字符的命令,自然就会冒出字符。用颜色名就写 \color{gray},用灰度值就写 \color[gray]{0.5},二者取其一。
% Palatino, bold, slanted — for the dropped capital only
\renewcommand{\LettrineFontHook}{\fontfamily{ppl}\fontseries{bx}\fontshape{sl}}
% Grey. NOT \color{gray}{0.5} — that silently prints "0.5" beside the cap.
\renewcommand{\LettrineFontHook}{\color[gray]{0.5}}
% Drop the small capitals on the run-on text
\renewcommand{\LettrineTextFont}{\rmfamily}
% Three lines tall, hanging 20% of its width into the margin
\lettrine[lines=3, lhang=0.2]{T}{his is} the opening paragraph of a chapter.
% A slanted letter wants its own contour:
\lettrine[lines=4, lraise=0.1, nindent=0em, slope=-.5em]{V}{oici} le texte.会出问题的场合:段落中间、列表里、双栏中
\lettrine 必须置于段首,前面一旦有可打印的内容,它就会悄无声息地出问题。 编译 Some words come first. \lettrine{L}{orem} …,既无错误也无警告,但「Some words come first.」被单独留在一条缩进的短行上,首字母和环绕从它下面才开始。\lettrine 是为整段设置 \parshape 的,因此排在它之前的内容就被撇在这套设计之外了。另外,前面加 \noindent 并不会把它弄坏——lettrine.sty 自己就会发出 \noindent,再写一个也无害。真正破坏它的不是空白,而是会打印出来的内容。
列表内部不能用。 这是宏包手册明说的,实测也把症状摆得很清楚。在 itemize 的 \item 之后紧接着写 \lettrine{I}{nlist},编译能通过,不报任何警告,环绕看上去也像模像样——可一放大就会看到,项目符号(•)被印在了首字母的左上角,与之重叠。原因很直白:\item 的标记和 \lettrine 的首字母都由 \llap 放到左边距旁的同一个位置。在 quote、quotation、abstract 里它工作正常;在 center 里则只有 [lines=1] 可用。另外,若必须在以 \lettrine 开头的段落内部插入列表,手册要求在列表结束后立刻写上 \parshape=0(在列表前后另起一段也可以)。
在双栏下,同一个 lines= 值给人的观感完全不同。 实测:标准 article 加上 twocolumn 后,\textwidth 仍为 469.0pt,而 \columnwidth 只有 229.5pt(\columnsep 为 10.0pt)。排版宽度不到原来的一半,可首字母的高度由 \baselineskip 决定,并不随之改变。于是首字母占栏宽的比例大约翻了一倍;一旦写成 lines=4,前四行就短得离谱,排出来一行行字间大开,很不好看。双栏中使用时,lines 保持 2,loversize 留在 0,lhang 也宜克制。此外,在右栏里 lhang 探出的方向不是页面外白,而是栏间距(\columnsep),务必用眼睛确认它没有挤到隔壁栏的正文。
想把中日文的第一个字放大时:实际会发生什么
把汉字交给 \lettrine,编译能通过,首字也确实排大了——但尺寸是按西文字体那一侧算出来的。 用 upLaTeX 加 jsarticle 排 \lettrine{吾}{輩は猫である。},没有报错,可日志里出现了 LaTeX Font Warning: Font shape OT1/cmr/m/n in size <31.53638> not available (Font) size <24.88> substituted。因为 lettrine 用来定高的是 \LettrineTestString(默认 EFTZ)以及当时的西文字体,而不是中日文字体。加上 \usepackage{lmodern} 可以让这条警告消失,但环绕缩进与中日文方块字面对不齐的问题依然存在。此外,第二个参数默认的 \scshape 对假名和汉字毫无作用——西文里理所当然的「大首字母接小型大写」这一视觉过渡,在这里根本不成立。
实务上的判断由此而来。若只是想让中日文章首的第一个字醒目,用标题字号与行数分配,或者靠缩进与留白来处理,要比硬把 \lettrine 塞进去可靠得多。若非要做下沉不可,就得在 \LettrineFontHook 里放上选中日文字体的命令,用 refstring= 把定高的基准换成实际要用的那个字,再手工调 nindent 与 findent。无论如何,中日文方正的字面本就不像西文首字母那样适合「下沉」。先打样出来用眼睛看过,再决定要不要采用。
什么时候加:正文定稿之前不要装饰
首字下沉不是帮助理解的装置,而是为章节开头定调的装饰。所以它要最后才加。 lines 与 lhang 的合适取值取决于段落长度和行的断法,因此每添一段正文都要重新检查一遍。论文、报告、规格书这类格式既定的文档,请不要用。它的用武之地在随笔、小册子,以及版面设计本就欢迎装饰的书籍章首。一旦决定采用,就要在同一份文档里保持同一条规则——这一章两行、那一章三行的参差,正是让装饰不再成其为装饰的典型做法。
- 只用在章首的第一段。 避开列表内部、
center内部([lines=1]除外),以及比首字母还短的段落。 - 正文定稿之前不要插入。
lines与lhang取决于段落长度和行的断法。 - 字体务必选可任意缩放的。 载入
lmodern之类,并核对.log里的Targeted height与Lettrine height是否接近。 - 优先用文字首字母,而非图像首字母。 这样读者才能检索和复制正文。
- 中日文章首要先判断西式首字下沉是否适合这个版面。 不适合就改用标题字号和留白来处理。