LaTeX에서 수식을 미세 조정할 때 쓰는 도구는 거의 모두 하나의 발상에서 나옵니다. 겉모습과 그 요소가 차지하는 치수(높이・깊이・너비)를 떼어 놓는 것 입니다. \smash는 키 큰 것의 높이를 0으로 세게 하고, \vphantom은 아무것도 찍지 않으면서 높이만 확보하며, \rlap은 글자를 찍으면서 너비를 0으로 만듭니다. 그래서 「근호가 든 그 줄만 행간이 벌어진다」 「이웃한 \sqrt 의 천장이 안 맞는다」 「합 기호 아래 조건이 식을 옆으로 벌린다」 같은 증상이 모두 같은 사고방식으로 풀립니다. 이 페이지는 증상에서 찾아가는 형태 로 \smash, \phantom, \mathstrut, \rlap, \raisebox, 그리고 \mathrm과 \operatorname의 차이를 실측값과 함께 늘어놓습니다.
증상으로 도구 찾기
먼저 한눈에 보는 표입니다. 모두 인쇄 결과를 마지막에 다듬기 위한 도구 이고, 식의 의미는 전혀 바꾸지 않습니다. 그래서 순서로는 수식을 먼저 담백하게 쓰고, 눈에 보이는 흠이 난 자리에만 나중에 대는 것이 정답입니다. 미리 \smash나 \phantom을 흩뿌려 두면 글꼴이나 본문 폭을 바꿀 때 오히려 어긋납니다. 첫 열의 명령 이름이 그대로 검색어가 되므로, 증상을 떠올린 뒤에 찾아보세요.
| 명령 | 고칠 수 있는 증상 | 출처 |
|---|---|---|
\smash | 키 큰 요소가 그 줄만 행간을 벌린다 | LaTeX 커널([t]/[b]는 amsmath) |
\vphantom | 이웃한 근호나 줄의 높이가 맞지 않는다 | plain TeX(LaTeX에서 그대로 사용 가능) |
\mathstrut | 같은 일을 인수 없이. 둥근괄호 하나만큼의 높이를 확보 | plain TeX. 정의가 그대로 \vphantom( |
\phantom | 여러 줄에서 자리를 맞추고 싶은데 왼쪽 길이가 다르다 | plain TeX. 폭만 필요하면 \hphantom |
\mathclap | 합이나 곱 아래의 긴 조건이 식 전체를 옆으로 벌린다 | mathtools(\mathllap/\mathrlap도 같은 묶음) |
\rlap | 글자를 찍되 너비로는 세지 않게 하고 싶다 | plain TeX. 왼쪽으로 내미는 \llap도 마찬가지 |
\overset | = 등의 바로 위에 임의의 기호를 얹고 싶다 | amsmath(바로 아래는 \underset) |
\operatorname | 직접 만든 여러 글자 연산자 앞뒤에 간격이 들어가지 않는다 | amsmath. 극한을 아래에 두려면 \operatorname* |
\raisebox | 어떤 요소만 정해진 양만큼 위아래로 옮기고 싶다 | LaTeX 커널. 높이와 깊이도 덮어쓸 수 있음 |
\! | 기호끼리 너무 떨어져 있다(중적분 \int\int 등) | plain TeX. \,의 정반대인 −3mu |
근호가 든 줄만 행간이 벌어진다 — \smash
\smash{...}는 내용을 높이도 깊이도 0인 상자로 다루게 합니다. 잉크는 그대로 찍히지만 TeX이 세로 치수를 0으로 보므로 행간을 넓힐 판단을 하지 않게 됩니다. 실측하면 $\sqrt{1-x^2}$는 높이 9.13329pt, 깊이 1.26668pt, 너비 35.75691pt입니다. 이것을 \smash로 감싸면 높이 0.0pt, 깊이 0.0pt, 그리고 너비는 35.75691pt 그대로 였습니다. 세로만 0이 되고 가로는 전혀 건드려지지 않았음이 숫자로 드러납니다.
% the radical inside the fraction pushes this line away from the one above
$y = \frac{1}{\sqrt{1 - x^2}}$
% zero its vertical size, and the leading returns to normal
$y = \frac{1}{\smash{\sqrt{1 - x^2}}}$amsmath를 불러오면 \smash에 선택 인수 가 붙어 위아래를 따로 다룰 수 있게 됩니다. \smash[t]{...}는 높이만 0으로 하고 깊이는 남기며, \smash[b]{...}는 깊이만 0으로 하고 높이는 남깁니다. 재어 보면 \smash[t]{\sqrt{1-x^2}}는 높이 0.0pt, 깊이 1.26668pt였고, \smash[b]{\sqrt{1-x^2}}는 높이 9.13329pt, 깊이 0.0pt였습니다. 노린 쪽만 깔끔히 사라졌습니다. 이 [t]/[b]는 LaTeX 커널의 \smash에는 없고 amsmath가 명령을 덮어써서 더한 것입니다(인수 없는 \smash 자체는 plain TeX 시절부터 있었고 LaTeX 커널에도 들어 있습니다).
% the descender of y drops the middle radical below the other two
$\sqrt{x} + \sqrt{y} + \sqrt{z}$
% smash away only the depth of y, and all three line up
$\sqrt{x} + \sqrt{\smash[b]{y}} + \sqrt{z}$amsmath가 스스로 드는 예가 이 차이를 깔끔히 보여 줍니다. \sqrt{x} + \sqrt{y} + \sqrt{z}에서는 y에 디센더(아래로 내려가는 부분)가 있어 가운데 근호만 살짝 내려갑니다. 숫자로 보면 $\sqrt{y}$는 높이 7.0305pt, 깊이 3.36946pt이고 $\sqrt{x}$는 높이 8.00272pt, 깊이 2.39725pt입니다. 그런데 $\sqrt{\smash[b]{y}}$를 재면 높이 8.00272pt, 깊이 2.39725pt——$\sqrt{x}$와 소수점 아래까지 완전히 일치 했습니다. 깊이만 지웠는데 근호가 x 위에 있을 때와 똑같은 치수로 돌아온 것입니다.
주의할 점이 둘 있습니다. 첫째, 사라지는 것은 치수뿐이고 잉크는 남으므로 눌린 요소가 윗줄을 파고들 수 있습니다. 행간이 빡빡한 본문에서는 고친 결과를 반드시 눈으로 확인하세요. 둘째, 오래된 설명에는 「문단 첫머리에서 \smash를 쓸 때는 \leavevmode를 앞에 두라」고 적혀 있곤 하지만, 현재의 LaTeX 커널에서는 그럴 필요가 없습니다. latex.ltx의 \finsm@sh는 \leavevmode@ifvmode\box\z@로 끝나며 수직 모드 처리를 스스로 합니다. 실제로 문단 첫머리에서 \smash를 써도 오류가 나지 않았습니다.
이웃한 근호의 천장이 맞지 않는다 — \vphantom과 \mathstrut
\smash가 「높은 것을 내리기」라면, \vphantom은 「낮은 것을 올리기」라는 정반대 조작 입니다. \vphantom{...}는 인수와 같은 높이・깊이를 가지되 너비가 0이고 아무것도 찍지 않는 상자를 만듭니다. 실측하면 $\vphantom{a^2}$는 높이 8.14003pt, 너비 0.0pt입니다. 짝을 이루는 $\hphantom{a^2}$는 높이 0.0pt, 너비 9.77202pt이고, 둘 다 지닌 $\phantom{a^2}$는 높이 8.14003pt, 너비 9.77202pt였습니다. 세로만, 가로만, 둘 다 라는 세 가지가 가지런히 갖춰져 있음을 알 수 있습니다. 낮은 쪽 요소에 높은 쪽 내용을 \vphantom으로 넣어 주면, 아무것도 보이지 않은 채 높이만 일치합니다.
% level the tops of several radicals with one strut each
$\sqrt{\mathstrut a}\;\sqrt{\mathstrut a^2}\;\sqrt{\mathstrut b}$
% or match a specific height by passing the taller content
$\sqrt{a} \;\sqrt{\vphantom{a^2}\,a}$매번 맞출 대상의 내용을 적기가 번거로울 때를 위해, 인수 없는 지름길 \mathstrut가 있습니다. plain TeX에 적힌 그 정의는 \def\mathstrut{\vphantom(} 입니다. 내용물은 「보이지 않는 여는 둥근괄호」 하나뿐입니다. 수식에서 둥근괄호는 알맞게 키가 크고 글자 크기를 따라가므로, 줄 높이를 맞추는 기준자로 안성맞춤입니다. 실측도 들어맞습니다. $($는 높이 7.5pt, 깊이 2.5pt입니다. $a$는 높이 4.30554pt, 깊이 0.0pt이지만 $\mathstrut a$로 하면 높이 7.5pt, 깊이 2.5pt——둥근괄호의 치수 그대로——이고 너비는 5.28589pt로 변하지 않습니다. 각 요소의 머리에 하나씩만 두면 모두 둥근괄호 하나만큼의 높이로 맞춰집니다.
align에서 = 위치 맞추기 — \phantom과 \MoveEqLeft
맞추고 싶은 식 자체를 \phantom에 넘깁니다. 변형을 이어서 쓸 때 둘째 줄부터는 좌변을 빼고 =부터 시작하고 싶어지지만, 맨 공백으로 밀어내면 글꼴이나 식이 바뀌는 순간 어긋납니다. \phantom{f(x)}라고 쓰면 f(x)를 실제로 조판한 것과 똑같은 너비의 공백이 생기므로 =가 저절로 세로로 맞습니다. 손으로 세어 늘어놓은 \quad와 달리 내용이 바뀌면 공백의 너비도 함께 바뀌는 것이 장점입니다.
\begin{align*}
f(x) &= x^2 + 2x + 1 \\
\phantom{f(x)} &= (x + 1)^2
\end{align*}
% mathtools: when the first line is too long to keep on one row
\begin{align*}
\MoveEqLeft f(x, y, z) = a + b \\
&= c + d
\end{align*}반대로 첫 줄의 좌변이 너무 길어 = 자리에 들어가지 않을 때는 mathtools의 \MoveEqLeft를 쓸 수 있습니다. 첫 줄을 정렬 위치보다 왼쪽으로 내보내고, 이후 줄이 그 아래에 자연스럽게 놓이도록 칸을 만듭니다. 줄머리에 두기만 하면 되고 &를 직접 셀 필요가 없습니다. 한편 \phantom과 \hphantom의 일반적인 구조, 그리고 수식 간격 전반은 「첨자와 간격」 페이지가 자세히 다룹니다.
너비를 갖지 않게 놓기 — \rlap, \llap, \mathclap
\smash의 가로 방향 판 이 이 무리입니다. \rlap{...}는 내용을 찍으면서 상자의 너비를 0으로 만들어 오른쪽으로 넘치게 합니다. plain TeX의 정의는 한 줄로, \def\rlap#1{\hbox to\z@{#1\hss}}——「너비 0인 상자를 만들고 남는 만큼은 무한히 늘어나는 글루로 오른쪽에 흘려보낸다」, 그것뿐인 장치입니다. 실측에서도 \rlap{XX}의 너비는 0.0pt, 맨 XX는 15.00003pt였습니다. 왼쪽으로 흘리는 \llap은 \hss의 위치가 앞으로 올 뿐입니다. 표의 칸 밖으로 나가는 주석이나 행 번호를 판면 밖으로 내보내는 용도로 쓰입니다.
수식 안에서 같은 일을 하고 싶으면 mathtools의 \mathclap(좌우 대칭으로 넘침), \mathllap(왼쪽으로), \mathrlap(오른쪽으로)을 씁니다. 전형적인 예는 합 기호 아래의 긴 조건으로, \sum_{\mathclap{1 \le i \le j \le n}} a_{ij} 처럼 감싸기만 하면 식의 너비가 연산자만큼으로 돌아옵니다. 이 무리와 \smashoperator, 그리고 본문용 \clap은 mathtools 페이지에서 자세히 다룹니다. 한편 조건을 가로로 좁히는 대신 여러 줄로 쌓고 싶을 때는 amsmath의 \substack{...}이 정답입니다. \sum_{\substack{0<i<m \\ 0<j<n}} 라고 쓰면 두 조건이 \\로 나뉘어 합 기호 아래에 두 줄로 놓입니다.
수식 안에 글자 쓰기 — \text, \mathrm, \operatorname의 차이
셋의 차이는 주변 서체를 물려받는가 와 연산자로서의 간격이 들어가는가, 이 두 점으로 끝납니다. 먼저 서체입니다. \text(amsmath에 딸린 amstext가 정의)는 주변 본문 서체를 그대로 물려받고, \mathrm은 언제나 곧은 로만체로 고정 합니다. 실측이 명쾌합니다. \textit{...} 안에서 \text{ab}는 14.24867pt인 데 비해 \mathrm{ab}는 14.61809pt입니다. \textbf{...} 안에서는 \text{ab}가 15.64928pt인 데 비해 \mathrm{ab}는 역시 14.61809pt——\mathrm은 문맥이 바뀌어도 한 자리도 다르지 않게 같았습니다. 본문과 같은 어조로 읽히게 하고 싶은 말에는 \text, 늘 곧게 조판해야 하는 단위나 첨자 라벨에는 \mathrm을 씁니다.
두 번째 점인 간격이 \mathrm과 \operatorname을 가릅니다. \operatorname(amsmath에 딸린 amsopn이 정의)은 내용을 연산자(\mathop)로 다루므로 앞뒤에 자동으로 한 숨만큼의 간격이 들어갑니다. 재어 보면 $\mathrm{max} x$가 24.32645pt, $\operatorname{max} x$가 25.99307pt——차이는 1.66662pt, 정확히 3mu짜리 가는 간격 하나입니다. 양쪽에 피연산자가 있는 $a \mathrm{mod} b$와 $a \operatorname{mod} b$에서는 28.74428pt 대 32.07753pt로 차이가 3.33325pt 곧 6mu(좌우 각 3mu)입니다. 흥미롭게도 뒤에 (가 이어지는 $\mathrm{max}(x)$와 $\operatorname{max}(x)$는 둘 다 32.10425pt로 완전히 같았습니다. TeX이 연산자와 여는 괄호 사이에는 간격을 넣지 않는 규칙이기 때문입니다. 그러니 괄호가 붙은 예만 보고 「같다」고 결론짓는 것은 성급합니다. 극한을 기호 아래에 두고 싶으면 별표가 붙은 \operatorname*{max}_{x}를 씁니다(실측 18.61118pt, 별표 없는 쪽은 23.6459pt로 옆에 붙습니다).
\[
x_{\text{total}} \quad x_{\mathrm{total}}
\qquad
a \operatorname{mod} b \quad a \mathrm{mod} b
\]
% define it once in the preamble instead of repeating \operatorname
\DeclareMathOperator{\rank}{rank}
\DeclareMathOperator*{\argmax}{arg\,max}같은 연산자를 여러 번 쓸 거라면 그때마다 \operatorname을 치기보다 프리앰블에서 한 번 정의해 두는 편이 확실합니다. amsmath의 \DeclareMathOperator{\rank}{rank}는 \rank를 연산자로 만들고, 별표가 붙은 \DeclareMathOperator*{\argmax}{arg\,max}는 극한을 아래에 두는 판을 만듭니다. 이름과 철자가 한곳에 모이므로 나중에 표기를 바꿀 때도 한 줄이면 끝납니다.
위아래로 옮기기와 좁히기 — \raisebox와 \!
\raisebox{양}{내용}은 내용을 지정한 양만큼 들어 올립니다(음수를 주면 내립니다). 실측하면 X는 높이 6.83331pt, \raisebox{2pt}{X}는 높이 8.83331pt——정확히 2pt 올라갔습니다. 여기에 선택 인수 둘을 더해 \raisebox{양}[높이][깊이]{내용}이라고 쓰면 주위에 알리는 높이와 깊이를 덮어쓸 수 있습니다. \raisebox{2pt}[0pt][0pt]{X}를 재면 높이 0.0pt, 깊이 0.0pt였습니다. 옮긴 뒤 \smash와 같은 「치수 0」으로 만드는 합동 기술입니다. 기호 위치를 아주 조금 손보고 싶을 때, 글꼴을 바꿔 위아래가 어긋났을 때 효과가 있습니다.
마지막으로 기호끼리 너무 떨어져 있는 경우입니다. 음수 가는 간격 \!는 plain TeX에서 \def\!{\mskip-\thinmuskip}로 정의되어 있어 \,(3mu)의 정확한 반대, 곧 −3mu 입니다. 실측으로 $ab$가 9.57755pt, $a\,b$가 11.24417pt(+1.66662pt), $a\!b$가 7.91092pt(−1.66663pt)——깔끔하게 대칭이었습니다. 전형적인 자리는 중적분으로, $\int\int$는 14.99997pt로 사이가 너무 벌어져 별개의 적분 둘로 보입니다. 여기에 \! 를 둘 끼운 $\int\!\!\int$를 재면 11.66672pt. 그리고 amsmath의 전용 명령 $\iint$도 11.66672pt——소수점 아래까지 완전히 일치 했습니다. 즉 예스러운 \int\!\!\int는 전용 명령과 조금도 다르지 않은 결과를 냅니다. 그렇더라도 뜻이 분명한 \iint, \iiint가 있다면 그쪽이 읽기 좋고, \!는 기성 명령이 없는 자리를 위한 도구로 여기는 편이 좋습니다.
\[
\int\int f \, dA
\qquad
\int\!\!\int f \, dA
\qquad
\iint f \, dA
\]
% an arbitrary symbol set squarely above another
\[
a \overset{!}{=} b, \qquad x \overset{?}{=} y,
\qquad A \overset{f}{\longrightarrow} B
\]마지막 한 가지, = 바로 위에 기호를 얹는 이야기입니다. ^와 _로 쓰는 첨자는 기호의 오른쪽 위・오른쪽 아래 에 붙으므로 바로 위나 바로 아래에는 오지 않습니다. amsmath의 \overset{위}{바탕}과 \underset{아래}{바탕}이 그 역할을 맡으며, \overset{!}{=}는 「같아야 한다」를, \overset{?}{=}는 「이것이 같은가」를 나타내는 관용 표기입니다. 두 번째 인수가 바탕, 첫 번째 인수가 얹는 것입니다. 화살표에 적용하거나 중첩하는 등 더 들어간 사용법은 「위아래 장식」 페이지에서 다룹니다.