長さと空白

「ここを 2cm あけて」と LaTeX に書けば、たしかに 2cm あきます。ところが同じ \vspace{2cm} がページの先頭に落ちた瞬間、その 長さ は跡形もなく消えます。バグではありません。LaTeX の空白は動かない寸法ではなく、伸び、縮み、要らなくなれば捨てられる グルー(glue) だからです。このページでは、ptbp がなぜ 0.375% ずれるのか、em が同じ 10pt でもフォントごとに変わるのはなぜか、\hspace* の星は何を守っているのか——長さの単位、空白の命令、ラバー長を、その「捨てられる」という一点から読み解きます。

ptbp の違い——LaTeX の長さの単位

長さは必ず 数値 + 単位 で書きます。12pt2.5cm-3mm のように小数も負の値も使えますが、単位を落とすと組版は ! Illegal unit of measure (pt inserted). で止まります——\hspace{2}\setlength{\mylen}{5} と書いてしまったときに出る、LaTeX でもっともよく見るエラーの一つです。単位そのものは二系統に分かれます。フォントに関係なく値が決まる 絶対単位ptbpincmmmpc)と、いま組んでいるフォントから値を読み出す フォント相対単位emex)です。

絶対単位の基準は pt、TeX ポイントです。Knuth は英米の活版業界が使っていた定義をそのまま採用しました——1 インチ = 72.27pt。TeX はこれと並んで、もう一つのポイントを抱えています。ちょうど 1/72 インチと定義された bp(big point) で、PostScript が、そしてのちに PDF が標準にしたきりのよい数のほうです。この二つは等しくありません。1bp = 1.00375pt ちょうど、つまり big point のほうが 0.375% 大きく、100bp100.375pt になります。PDF の座標系そのものが 1/72 インチ刻みなので、EPS や PDF のバウンディングボックス(BoundingBox)に書かれた数値はすべて bp。図版を \includegraphics[width=100pt] から [width=100bp] に書き換えると、まさにこの 0.375% だけ大きさが変わります。ミリで書くほうが安全なのは、この取り違えが起こらないからです。

単位正体・換算使いどころ
ptTeX ポイント。1in = 72.27pt長さ全体の基準。フォントサイズもこの単位
bpビッグポイント。1bp = 1.00375pt(72bp = 1in)PostScript/PDF のポイント。BoundingBox の単位
inインチ。1in = 72.27pt米国式の用紙寸法に
cmセンチメートル。1cm = 28.45274pt余白・図版寸法の実務標準
mmミリメートル。1mm = 2.84526pt細かい寸法指定に
pcパイカ。1pc = 12pt欧文組版の伝統単位。まとまった段幅などに
ddディド点。1157dd = 1238pt(≈ 1.07pt)大陸ヨーロッパの活版伝統
ccシセロ。1cc = 12dd = 12.8401ptディド系のパイカにあたる
spスケールドポイント。1pt = 65536spTeX が内部で長さを刻む最小単位。手書きはしない
pxピクセル。既定は 1px = 1bp = 1.00375ptpdfTeX 系のみ。\pdfpxdimen で変えられる
em現在のフォントが申告するクワッド(\fontdimen6フォント相対。字下げ・横方向のアキに
ex現在のフォントの x ハイト(\fontdimen5フォント相対。小文字の高さに揃えたい縦の微調整に
mu数式単位。18mu = 1em数式モード専用。\, は 3mu、\; は 5mu

表の下のほうにある sp(scaled point) は、TeX が内部で長さを刻む最小の単位で 1pt = 65536sp。自分で書くことはまずありませんが、この刻みが TeX の精度と限界の両方を決めています。1sp はおよそ 5.4 ナノメートル——可視光の波長(400〜700nm)よりはるかに細かい——一方で、TeX が保持できる最大の長さ \maxdimen16383.99998pt、メートルに直すとわずか 約 5.76m です。どちらの数字も、長さは sp 単位の整数で 2^30 未満でなければならない、という同じ一つの制約から出ています。ヨーロッパ大陸の活版に由来する dd(ディド点、1157dd = 1238pt)cc(シセロ、1cc = 12dd) もそのまま使えますが、現代の文書ではまず出番がありません。

emex はフォントによって変わる

em は「フォントサイズ」ではありません。いま有効なフォントが自分で申告している クワッド(quad)、TeX の内部でいう \fontdimen6 の値です。だから同じ「10pt」でも答えが変わります。10pt の Computer Modern Roman で 1em はちょうど 10.00002pt ですが、同じ 10pt のタイプライタ体 Computer Modern Typewriter に切り替えると 1em = 10.4999pt、イタリックでは 10.22217pt になります。ついでに言えば、よく使われる「em は大文字 M の幅」という説明も実測には耐えません。cmr10 の M は 9.16669pt で、1em より狭いのです。この名前は、em 込め物が字身と同じ正方形だった金属活字時代の名残であって、実際の数値はフォント側が決めています。

ex も同じ仕組みで、こちらはフォントが申告する x ハイト\fontdimen5)です。10pt の Computer Modern Roman では 4.30554pt、同じ 10pt でもサンセリフの Computer Modern Sans では 4.44444pt になります。この二つの使い分けは「横だから em、縦だから ex」という方向の話ではなく、何に揃えたいか の話です。字送りに揃えたい空きは em、小文字の高さに揃えたい微調整は ex が自然に効きます。数式モードにはさらに mu(math unit) があり、18mu = 1em\quad\hskip1em\qquad はその倍の 2em で、細いアキの \, は数式では 3mu、本文では 0.16667em(= 1/6 em)のカーンとして入ります。太めの \;5mu、中くらいの \:amsmath を読み込んだときに使えるようになる 4mu です。

latex
% absolute units: the same length whatever font is active
\hspace{12pt}  \hspace{2.5cm}  \hspace{-3mm}  \hspace{100bp}

% font-relative units: the font decides the value
\hspace{1em}   \vspace{2ex}

% proof that em follows the font, not the point size
\rmfamily \the\dimexpr 1em\relax   % 10.00002pt at 10pt
\ttfamily \the\dimexpr 1em\relax   % 10.4999pt  at 10pt

ラバー長——plusminus は何をしているのか

plus は伸びしろ、minus は縮みしろを与えます。12pt のように動かない長さを リジッド長(rigid length)1cm plus 2mm minus 1mm のように余地を持つ長さを ラバー長(rubber length) と呼び、後者は「ふだんは 1cm、必要なら 1.2cm まで伸び、0.9cm まで縮む」という意味になります。TeX にとってこれは特別な機能ではなく、行組みでも段落でもページでも、空白は基本的にすべてこの伸縮する グルー です。行を左右の余白にぴったり揃えられるのは、単語間の空きがラバー長だからにほかなりません。逆に言えば、\vspace{12pt} のように遊びのない空きを並べると、TeX から調整の余地を奪うことになります。

latex
% rigid: exactly 1cm, always
\vspace{1cm}

% rubber: 1cm normally, up to 1.2cm, down to 0.9cm
\vspace{1cm plus 2mm minus 1mm}

% infinite stretch: 0pt at rest, grows without limit
\vspace{\fill}

LaTeX の \fill はスキップレジスタで、中身は 0pt plus 1fill——自然長は 0、伸びしろは 無限 です。無限は有限に必ず勝つので、同じ行や同じ段に \fill が一つでもあれば、有限の plus しか持たない普通のグルーはまったく伸びなくなります。TeX の無限には三段階あって fil < fill < filll\hfilplus 1fil\hfillplus 1fill なので、同じ行に両方あれば \hfill が余りを総取りします。比率で分けたいときは \stretch{n}(= 0pt plus n fill)を使い、\hspace{\stretch{2}}\hspace{\stretch{1}} を並べれば残りが 2:1 に分かれます。同じ強さの \fill を二つ置けば等分です。

では、この伸縮は縦方向でも本当に働いているのでしょうか。働く場合と働かない場合があります。ページ下端をきっちり揃える \flushbottom のとき、TeX はそのページに載っている伸びるグルー——段落間の \parskip(既定は 0pt plus 1pt)、見出しの前後のアキ、\bigskip など——を少しずつ引き伸ばして版面の高さちょうどに合わせます。ところが \raggedbottom ではそれが起きません。理由は LaTeX カーネルのたった一行で、\raggedbottom は本文の末尾に \vskip 0pt plus.0001fil というグルーを一つ足すだけです。この極小の 無限 の伸びしろがページ上のあらゆる有限の plus を出し抜いて遊びを独り占めするので、本文中のグルーは自然長のまま残り、余りはすべてページ末に落ちます。そして標準クラス(articlereportbook)は、片面 なら \raggedbottomtwosidetwocolumn なら \flushbottom を自動で選びます。article の既定は oneside なので、既定の article では \vspace に書いた plusminus はページ合わせにほとんど動員されません。効かせたければ \flushbottom を宣言します。

\hspace\hspace* の違い、\hfill\dotfill

行内に水平の空きを入れるのは \hspace{長さ} です。\hspace{2cm} と書けば 2cm あきます——ただし、その空きが行の端に来なければ。TeX は段落を行に割るたびに、切れ目に隣接するグルーを捨てます。行末に空白がぶら下がったり、次の行の頭が理由もなく押し込まれたりしないための規則です。星付きの \hspace*{長さ} はここを回避します。定義を覗くと、幅 0 の \vrule\nobreak を空きの直前に置いてから \hskip を出しているだけ。罫線はグルーではなく ボックス なので捨てられず、その後ろの空きはもう「切れ目の隣」ではなくなる、という仕掛けです。段落の 1 行目に強制的に字下げを入れたいときなどに効きます。

\hfill\hspace{\fill} と同じで、左右のものを行が許すかぎり引き離します。一語を行頭に、もう一語を行末に置く定番ですが、これもグルーなので行端では捨てられます。確実に残したいなら \hspace*{\fill} と書きます。空白ではなく 何かで埋めたい ときは、罫線を引く \hrulefill と点を並べる \dotfill があり、どちらも中身は \hfill に TeX のリーダー機構(\leaders\cleaders)を組み合わせたものです。目次の項目とページ番号のあいだのリーダー線も、記入欄の下線も、これで作られています。小さく決まった空きなら、フォントに連動する \quad1em)・\qquad2em)・\, のほうが、文字サイズを変えても見た目のバランスが崩れません——6pt と直書きした空きは、そうはいきません。

latex
Name:\hspace{2cm}Date:\par
\noindent Chapter 1\quad Introduction\dotfill 1\par
\noindent left\hfill centre\hfill right\par
\noindent Signature:\hrulefill\par
% 2:1 split of the leftover space
\noindent A\hspace{\stretch{2}}B\hspace{\stretch{1}}C\par
% survives even at the start of a line
\noindent\hspace*{2cm}forced indent

\vspace がページの先頭で消えるのはなぜか

同じ規則が縦方向にもそのまま働くからです。ページの切れ目でも TeX は隣接するグルーを捨てるので、\vspace{3cm} がページの先頭に落ちれば、その 3cm はまるごと消えます。実際に測ると、\newpage の直後に置いた \vspace{3cm} の寄与はきっかり 0 でした——「なぜかここだけ空きが効かない」の正体はたいていこれです。狙いは \hspace のときと同じで、ページ頭に説明のつかない白い帯を残さないこと。星付きの \vspace*{長さ} は同じ手口で回避します。高さ 0 の \hrule\nobreak を空きの直前に置くのです。改ページ位置がどこに来ても絶対に残ってほしい空き——章扉の上に決まった量のアキを取る、といった場面——では \vspace* を使います。

日常的な縦アキには、あらかじめ用意された三段階があります。\smallskip\medskip\bigskip で、標準の値はそれぞれ 3pt plus 1pt minus 1pt6pt plus 2pt minus 2pt12pt plus 4pt minus 4pt。10pt の文書では \baselineskip12pt ですから、\bigskip はおおむね一行分にあたります。三つとも中身はラバー長なので、ページの都合で少し伸び縮みします。ここで前の段落が効いてきます。この三つは星なしの \vspace として定義されている\vspace\smallskipamount など)ので、ページの境目では他のグルーと同じく容赦なく捨てられます。見出しの前に入れたはずのアキが、その見出しがページ頭に来た途端に消えるのはこれが理由です。残したいなら \vspace*{\bigskipamount} と書きます。縦方向の \fill\vfill(= \vspace{\fill})で、一行だけのページを縦中央に置いたり、署名欄をページ最下部まで押し下げたりするのに使います。

命令入るアキ切れ目で捨てられるか
\hspace{len}指定した幅の水平グルーはい(行端で消える)
\hspace*{len}同じ幅。直前に幅 0 の \vrule を置くいいえ
\hfill\hspace{\fill} と同じ。0pt plus 1fillはい
\hfil0pt plus 1fil\hfill より一段弱いはい
\stretch{n}0pt plus n fill。比率で空間を配分するはい
\hrulefill隙間を罫線で埋める \hfillはい
\dotfill隙間を点で埋める \hfill。目次のリーダーにはい
\quad\hskip1em。フォントに連動する固定アキはい
\qquad\hskip2em\quad の二倍はい
\,細いアキ。数式で 3mu、本文で 0.16667emいいえ(本文ではカーン)
\vspace{len}指定した高さの垂直グルーはい(改ページ位置で消える)
\vspace*{len}同じ高さ。直前に高さ 0 の \hrule を置くいいえ
\vfill\vspace{\fill} と同じ。縦に残りを押し広げるはい
\smallskip\vspace3pt plus 1pt minus 1ptはい
\medskip\vspace6pt plus 2pt minus 2ptはい
\bigskip\vspace12pt plus 4pt minus 4pt。10pt では約一行はい

\newlength\setlength\addtolength で長さを変数にする

同じ長さを文書のあちこちで使うなら、長さレジスタ を一つ作って名前で参照するほうが保守が楽です。\newlength{\mylen} で新しい長さを宣言し、\setlength{\mylen}{2em} で値を入れ、\addtolength{\mylen}{-1pt} で増減します。値を一か所で直せば参照しているすべての箇所が追随します。宣言は一度きりで、同じ名前をもう一度 \newlength すると ! LaTeX Error: Command \mylen already defined. になります。組んだ結果の寸法を測りたいときは \settowidth{\mylen}{Total:}(および \settoheight\settodepth)が便利で、その文字列を実際に組んだときの幅がそのまま入ります。値を確認したければ \the\mylen と書けば PDF に出力されます。

既存の長さもそのまま計算に使えます。\textwidth(本文の横幅)、\linewidth(いま組んでいる行の幅——minipage や箇条書きの中では \textwidth より狭くなります)、\baselineskip(行送り)、\parindent(字下げ量)、\parskip(段落間のアキ、既定は 0pt plus 1pt)。前に係数を置くだけで 0.8\textwidth のように倍率が書け、これは追加パッケージなしで動きます。ここに、エラーが出ないぶん厄介な落とし穴があります。calc を読み込まずに \setlength{\mylen}{\textwidth - 2em} と書いても、LaTeX は何も文句を言いません。しかし起きるのは引き算ではありません。\mylen には \textwidth がそのまま入り(既定の article なら 345.0pt)、残った - 2em本文の文字として組まれて しまいます。PDF に「- 2em」という文字列が現れて初めて気づく類のバグです。\usepackage{calc} を入れれば同じ行が正しく 324.99997pt になり、(\textwidth - 2em)/2 のような括弧つきの式も書けるようになります。

document.tex
\usepackage{calc}   % needed for + - * / inside \setlength
% ...
\newlength{\gutter}
\setlength{\gutter}{2em}
\addtolength{\gutter}{-1pt}

\newlength{\halfcol}
\setlength{\halfcol}{(\textwidth - \gutter) / 2}

\newlength{\labelw}
\settowidth{\labelw}{Total:}   % width of that text once typeset

\the\halfcol                   % prints the value, e.g. 162.49998pt
\noindent\hspace*{0.8\textwidth}right-aligned heading

まとめると、実務の判断は三つに集約できます。固定値の直書きは最後の手段 です——8cm と書いた瞬間、用紙サイズや余白を変えたときに比率が崩れます。0.8\textwidth2\baselineskip のように既存の長さを基準にした式なら、レイアウトを変えても壊れません。縦アキは既製の \smallskip\medskip\bigskip を優先し、生の \vspace{12pt} は本当に必要なときだけにすると、文書全体の呼吸がそろいます。そして 切れ目をまたいで絶対に残したい空きだけを星付き にする——星を付けなかった空きは、TeX が捨ててよいと判断した空きだからです。この三つを守るだけで、「なぜかここだけ空きが消える」という原因不明の事故はほとんど起きなくなります。