LaTeX는 텍스트, 수식, 그림을 먼저 박스 안에 넣은 뒤 그 박스들을 페이지에 배치합니다. 박스는 너비, 높이, 깊이라는 세 가지 치수를 가진 단단한 직사각형이며, 줄 나누기 과정은 그 내부를 들여다보지 않고 하나의 나눌 수 없는 단위로 취급합니다. 이 “박스에 담는다”는 생각을 이해하면 글자를 옮기고, 겹치고, 테두리를 두르고, 단을 만드는 작업이 모두 같은 원리의 응용으로 보입니다.
박스 모델
TeX 내부에서는 조판된 모든 재료가 치수를 가진 박스입니다. 문자 하나도 박스이고, 단어도 박스이며, 줄도 박스이고, 한 페이지 전체도 박스입니다. LaTeX는 줄과 단락을 만들 때 이 박스들을 늘어나고 줄어드는 공백으로 이어 붙인 뒤 가장 좋은 지점에서 줄과 페이지를 나눕니다. 핵심은 한번 하나의 박스로 묶인 내용은 다시 분할되지 않는다는 점입니다. 박스 안에서는 줄바꿈이 일어나지 않으며, 박스 전체가 하나의 단위로 다음 줄로 넘어갑니다.
LaTeX의 박스는 크게 두 종류로 나뉩니다. 첫째는 LR 박스(left-to-right box)입니다. 내용을 한 줄로만 배치하며 중간에서 줄을 나누지 않습니다. 가로로 너무 길어지면 여백 밖으로 튀어나갑니다. \mbox, \makebox, 테두리가 있는 \fbox가 여기에 속합니다. 둘째는 단락 박스입니다. 미리 정한 너비 안에서 내용을 줄바꿈하므로 여러 줄이나 여러 단락을 담을 수 있습니다. \parbox와 minipage 환경이 단락 박스입니다.
이 차이는 TeX의 모드와 대응합니다. LR 박스 안은 LR 모드로, 입력을 왼쪽에서 오른쪽으로 흘려 보낼 뿐 줄을 나누지 않습니다. 단락 박스 안은 (내부) 단락 모드로 전환되어 일반 본문처럼 줄 나누기가 작동합니다. 어떤 명령이 어떤 모드를 만드는지 의식하면 “왜 여기서 줄이 바뀌지 않는지”, “왜 아래로 길어지는지”가 분명해집니다.
LR 박스: 한 줄로 담기
가장 기본적인 LR 박스는 \mbox{...} 입니다. 내용을 하나의 박스에 봉해 넣고 줄바꿈과 하이픈 분할을 모두 금지합니다. 제품명 Mac OS X, 전화번호, 긴 화합물 이름처럼 중간에서 끊기면 안 되는 구를 \mbox로 감싸면 항상 한 줄에 유지됩니다. 값과 단위가 떨어지지 않게 하는 것처럼 작은 조정에도 유용합니다.
너비를 직접 정하고 싶을 때는 \makebox[width][position]{text} 를 사용합니다. [width]는 박스의 너비를 지정하고, [position]은 내용이 그 안의 어디에 놓일지 고릅니다. l은 왼쪽 정렬, c는 가운데 정렬(기본값), r은 오른쪽 정렬, s는 단어 사이 공백을 늘려 전체 너비에 맞게 양쪽 정렬합니다. \textwidth 같은 일반 길이뿐 아니라 내용의 자연스러운 크기를 나타내는 특수 길이도 쓸 수 있습니다. \width(내용의 너비), \height와 \depth, \totalheight(높이와 깊이의 합)입니다. 예를 들어 \makebox[2\width]{word}는 단어 너비의 두 배인 박스를 만듭니다.
특히 강력한 것은 너비 0 박스 \makebox[0pt][position]{text} 입니다. 박스의 너비가 0이므로 LaTeX는 내용을 조판하지만 가로 방향의 현재 위치를 전진시키지 않습니다. 따라서 뒤따르는 재료 위에 겹쳐 인쇄할 수 있습니다. [c]는 현재 위치를 중심으로 좌우에 걸치고, [r]은 왼쪽으로, [l]은 오른쪽으로 뻗습니다. 취소선, 겹쳐 찍기, 여백 주석 등에 쓰이며, 축약 명령 \rlap과 \llap(각각 오른쪽과 왼쪽으로 튀어나가는 너비 0 박스)도 같은 원리입니다.
테두리를 그리고 싶을 때는 \fbox{text} 와 \framebox[width][position]{text} 를 사용합니다. 내용 박스의 네 변에 선을 그립니다. \framebox의 [width][position]은 \makebox와 완전히 같습니다. 테두리 모양은 두 길이로 정해집니다. 선 두께인 \fboxrule(기본값 0.4pt) 과 테두리와 내용 사이의 여백인 \fboxsep(기본값 3pt) 입니다. \setlength로 바꿀 수 있으며, 예를 들어 \setlength{\fboxsep}{0pt}로 하면 테두리가 내용에 딱 붙습니다. 이들은 한 줄용 LR 박스이므로 여러 줄을 둘러싸려면 다음 절의 단락 박스와 함께 사용합니다(더 복잡한 테두리는 “테두리”를 참조).
Do not break \mbox{Mac OS X} here.
% a 4cm box, contents flush right, then framed
\framebox[4cm][r]{right} \\[1ex]
% zero-width box: the word overprints what follows
X\makebox[0pt][l]{\,/} Y % prints an X/ over the gap before Y위 예제에서 \mbox로 감싼 구는 항상 한 줄에 머물고, \framebox[4cm][r]는 너비 4 cm의 테두리 안에 내용을 오른쪽 정렬로 놓으며, 마지막 너비 0 박스는 X 바로 뒤에 사선을 겹쳐 찍습니다.
단락 박스: parbox와 minipage
너비를 정해 두고 내용이 줄바꿈되게 하려면 단락 박스를 사용합니다. 간단한 형태는 \parbox[position]{width}{text} 로, 주어진 {width} 안에서 내용을 하나의 단락으로 줄바꿈합니다. [position]은 이 박스를 주변 줄의 어디에 맞출지 지정합니다. c는 기본값으로 박스의 중심을 줄의 중심에 맞추고, t는 박스 첫 줄의 기준선을 주변 기준선에 맞추며, b는 마지막 줄의 기준선에 맞춥니다. 더 나아가 \parbox[position][height][inner-pos]{width}{text}로 높이와 내부 세로 정렬(t/c/b/s)까지 지정할 수 있지만, \parbox가 다룰 수 있는 것은 단일 단락뿐입니다. 여러 단락이나 목록은 넣을 수 없습니다.
더 자유로운 단락 박스는 minipage 환경입니다. \begin{minipage}[position][height][inner-pos]{width} … \end{minipage}처럼 쓰며, 인수의 의미는 \parbox와 같지만 내용은 작은 독립 페이지처럼 다루어집니다. 여러 단락, itemize 같은 목록, 심지어 verbatim까지 넣을 수 있어 단락 박스 중 실질적인 주력입니다. 한 가지 주의할 점은 내부에서 단락 들여쓰기(\parindent)가 0으로 초기화된다는 것입니다. 필요하면 \setlength{\parindent}{1em}처럼 직접 설정합니다.
minipage에는 고유한 각주 처리도 있습니다. 그 안에서 \footnote를 사용하면 각주는 페이지 하단이 아니라 minipage 바로 아래에 a, b, … 같은 소문자 표식으로 출력됩니다(전용 mpfootnote 카운터를 사용합니다). 표나 박스형 보조 설명 안에서 주석을 완결시키고 싶을 때 편리합니다. 반면 minipage는 내부에 플로트(figure/table)를 둘 수 없고, 페이지를 넘어 분할되지도 않습니다. 하나의 박스로 페이지에 들어맞아야 합니다.
minipage의 가장 흔한 활용은 나란한 단 구성입니다. 두 개의 minipage를 이어서 놓고 그 사이에 \hfill 같은 공백을 넣으면 간단한 2단 레이아웃이 됩니다. 그림과 설명문을 좌우로 놓거나 두 이미지를 나란히 배치할 때 자주 쓰입니다. 둘 다 [t]로 맞추면 높이가 다른 두 박스의 위쪽이 깔끔하게 정렬됩니다(더 본격적인 배치는 “플로트와 배치”를 참조).
\noindent
\begin{minipage}[t]{0.48\textwidth}
Left column. This minipage wraps text within 48\%
of the text width, and can hold several paragraphs,
lists, and even its own footnote.\footnote{Local note.}
\end{minipage}\hfill
\begin{minipage}[t]{0.48\textwidth}
Right column, top-aligned with the left one because
both use the optional \verb|[t]| argument.
\end{minipage}두 minipage는 각각 본문 너비의 48%를 차지하고, 사이의 \hfill이 나머지를 채워 전체 너비로 펼쳐지게 합니다. 둘 다 [t]를 사용하므로 줄 수가 달라도 위쪽이 맞습니다. 왼쪽 박스의 \footnote는 페이지 하단이 아니라 minipage 아래에 소문자 표식과 함께 나타납니다.
올리고 선 긋기: raisebox와 rule
박스를 세로로 옮길 때는 \raisebox{lift}[height][depth]{text} 를 사용합니다. {lift}가 양수이면 내용을 위로 올리고, 음수이면 아래로 내립니다. 흥미로운 부분은 선택 인수 [height]와 [depth]입니다. 이것들은 LaTeX에게 이 박스가 그만큼의 높이와 깊이를 가진 것처럼 보이게 하라고 알려주는 선언입니다. 실제로 보이는 모습과 별개로 주변 줄 간격은 이 선언값으로 계산됩니다. 예를 들어 \raisebox{0pt}[0pt][0pt]{a big symbol}은 실제로는 큰 내용을 그리면서도 높이와 깊이를 0으로 선언하므로 줄간격을 흔들지 않고 장식을 넣을 수 있습니다. 여기서도 \height, \depth, \totalheight 같은 특수 길이를 사용할 수 있습니다.
\rule[lift]{width}{height} 는 꽉 찬 직사각형, 즉 검은 박스를 그립니다. {width}와 {height}로 치수를 정하고, 선택 인수 [lift]로 기준선 위아래 위치를 조정합니다(음수이면 아래로 내림). 가로선을 그리기에 아주 적합하며, 예를 들어 \rule{0.5\linewidth}{0.4pt}는 줄 너비의 절반인 가는 선을 만듭니다.
\rule의 또 다른 모습은 스트럿(strut) 입니다. 너비를 0으로 한 \rule{0pt}{height}는 출력에는 보이지 않지만 그 높이만큼 자리를 확보하는 보이지 않는 박스입니다. 줄의 최소 높이를 강제하거나 표 셀에 여유를 줄 때 유용합니다. 줄 앞에 \rule{0pt}{2.6ex}를 놓으면 그 줄은 반드시 2.6 ex 이상의 높이를 갖습니다. LaTeX 표준 명령 \strut도 실제로는 \rule[-0.3\baselineskip]{0pt}{\baselineskip}입니다. 즉 현재 줄간격 전체에 해당하는 높이와 깊이를 가진 너비 0 스트럿입니다. 표의 선과 글자가 비좁게 맞붙는 것을 막는 대표적인 기법입니다.
% a centered horizontal rule
\noindent\hfil\rule{0.5\linewidth}{0.4pt}\hfil
% a strut forces a taller line / roomier table cell
\begin{tabular}{|l|}
\hline
\rule{0pt}{2.6ex}Tall, uncramped row \\
\hline
\end{tabular}
% align two differently sized boxes on a common baseline
big \raisebox{-0.4ex}{\Huge A} small박스 저장하고 재사용하기
같은 재료를 반복해서 사용한다면 한 번만 조판해 박스에 저장한 뒤 나중에는 꺼내 쓰기만 할 수 있습니다. 먼저 \newsavebox{\boxname}으로 저장용 박스(레지스터)를 하나 선언합니다. 다음으로 \sbox{\boxname}{text} 또는 \savebox{\boxname}[width][position]{text}로 내용을 채웁니다. 내용이 실제로 조판되는 것은 바로 이 순간 한 번뿐입니다. 필요한 곳에서 \usebox{\boxname}라고 쓰면 저장된 박스가 그대로 출력됩니다. 긴 표나 복잡한 그림처럼 조판에 비용이 드는 재료를 여러 곳에서 쓸 때 처리 속도를 높이고 모양을 완전히 일치시킬 수 있습니다.
저장용 박스는 LR 박스이므로 여러 줄 내용을 저장하려면 먼저 \parbox나 minipage로 감싸야 합니다. \begin{lrbox}{\boxname} … \end{lrbox}라는 환경 형태도 있으며, verbatim을 포함한 내용을 저장할 때 더 적합합니다. 또한 \sbox는 견고한(robust) 반면 \savebox는 취약한(fragile) 명령이므로, 절 제목 같은 “움직이는 인수” 안에서 후자를 사용할 때는 주의해야 합니다.
박스의 치수를 재려면 \settowidth{\len}{text}, \settoheight{\len}{text}, \settodepth{\len}{text}를 사용합니다. 이 명령들은 내용을 조판했을 때의 너비, 높이, 깊이를 지정한 길이 레지스터에 저장합니다. 박스 크기에 꼭 맞는 테두리나 밑줄을 그리는 등 정밀한 조정에 유용합니다.
\newsavebox{\mylogo}
\sbox{\mylogo}{\fbox{\textbf{Draft}}} % typeset once
% reuse the identical box as many times as you like
Header: \usebox{\mylogo} \dots\ Footer: \usebox{\mylogo}
% measure a box into a length, then rule under it
\newlength{\w}
\settowidth{\w}{Signature}
Signature\par\rule{\w}{0.4pt}\sbox 줄에서 “Draft”를 테두리 안에 한 번만 조판하고, 두 곳의 \usebox 호출이 그 동일한 박스를 꺼내 씁니다. 아래쪽에서는 \settowidth로 “Signature”의 너비를 재고, \rule로 정확히 그 너비의 밑줄을 그립니다.
박스 명령 한눈에 보기
| 명령 | 종류 | 역할 |
|---|---|---|
\mbox | LR 박스 | 내용을 한 줄에 고정; 줄바꿈과 하이픈 분할 금지 |
\makebox | LR 박스 | 너비와 위치 지정; [0pt]는 너비 0으로 겹쳐 인쇄 |
\framebox | LR 박스 | 테두리가 있는 \makebox(\fbox는 너비 지정 없는 형태) |
\parbox | 단락 박스 | 고정 너비 안에서 줄바꿈되는 단일 단락 박스 |
minipage | 단락 박스 | 단락, 목록, 각주를 담는 작은 페이지 |
\raisebox | 변형 | 내용을 위아래로 이동; 높이와 깊이를 다르게 선언 가능 |
\rule | 채움 박스 | 꽉 찬 직사각형; 너비 0이면 스트럿 |
\usebox | 저장 | \newsavebox + \sbox로 저장한 박스를 출력 |