“여기에 2cm 띄워라”라고 LaTeX 에 쓰면 정말로 2cm 가 벌어집니다. 그런데 똑같은 \vspace{2cm} 가 쪽 맨 위에 놓이는 순간, 그 길이 는 흔적도 없이 사라집니다. 버그가 아닙니다. LaTeX 의 공백은 고정된 치수가 아니라 늘어나고 줄어들며 필요 없어지면 버려지는 글루(glue) 이기 때문입니다. 이 페이지는 길이의 단위(pt, bp, em, ex), 실제로 공백을 만들어 내는 명령(\hspace, \vspace 와 별표 형태), 러버 길이를 하나의 줄기로 꿰어 봅니다. pt 와 bp 가 왜 0.375% 어긋나는지, 같은 10pt 인데 em 이 글꼴마다 달라지는 이유는 무엇인지, \hspace* 의 별표가 무엇을 지키는지가 그 줄기입니다.
pt 와 bp 의 차이 — LaTeX 의 길이 단위
길이는 반드시 숫자 + 단위 로 씁니다. 12pt, 2.5cm, -3mm 처럼 소수와 음수도 쓸 수 있지만, 단위를 빠뜨리면 조판이 ! Illegal unit of measure (pt inserted). 에서 멈춥니다. \hspace{2} 나 \setlength{\mylen}{5} 라고 썼을 때 나오는 메시지로, LaTeX 에서 가장 자주 보는 오류 중 하나입니다. 단위 자체는 두 갈래입니다. 글꼴과 무관하게 값이 정해지는 절대 단위(pt, bp, in, cm, mm, pc)와, 지금 쓰고 있는 글꼴에서 값을 읽어 오는 글꼴 상대 단위(em, ex)입니다.
절대 단위의 기준은 pt, 곧 TeX 포인트입니다. Knuth 는 영미 활판 업계가 쓰던 정의를 그대로 받아들였습니다. 1 inch = 72.27pt 입니다. TeX 은 여기에 두 번째 포인트를 함께 지니는데, 정확히 1/72 인치로 정의된 bp(big point)입니다. PostScript 가, 그리고 뒤이어 PDF 가 표준으로 삼은 딱 떨어지는 쪽입니다. 둘은 같지 않습니다. 1bp = 1.00375pt 로 정확히 떨어지며 big point 쪽이 0.375% 큽니다. 그래서 100bp 는 100.375pt 가 됩니다. PDF 의 좌표계 자체가 1/72 인치 눈금이므로 EPS 나 PDF 의 BoundingBox 에 적힌 숫자는 모두 bp 입니다. 그림을 \includegraphics[width=100pt] 에서 [width=100bp] 로 바꾸면 크기가 바로 그 0.375% 만큼 달라집니다. 그림 크기를 밀리미터로 적는 편이 안전한 이유는 이 혼동이 아예 생기지 않기 때문입니다.
| 단위 | 정체 / 환산 | 쓰이는 곳 |
|---|---|---|
pt | TeX 포인트. 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 = 65536sp | TeX 이 길이를 저장하는 최소 눈금. 직접 쓰지 않음 |
px | 픽셀. 기본값 1px = 1bp = 1.00375pt | pdfTeX 계열 전용. \pdfpxdimen 으로 변경 |
em | 현재 글꼴이 신고하는 쿼드(\fontdimen6) | 글꼴 상대. 들여쓰기와 가로 공백에 |
ex | 현재 글꼴의 x 높이(\fontdimen5) | 글꼴 상대. 소문자 높이에 맞춘 세로 미세 조정에 |
mu | 수식 단위. 18mu = 1em | 수식 모드 전용. \, 는 3mu, \; 는 5mu |
표 아래쪽에 있는 sp(scaled point)는 TeX 이 내부에서 길이를 새기는 가장 작은 눈금으로, 1pt = 65536sp 입니다. 직접 쓸 일은 거의 없지만, 이 눈금이 TeX 의 정밀도와 한계를 동시에 정합니다. 1sp 는 약 5.4 나노미터 로 가시광선의 파장(400~700nm)보다 훨씬 미세합니다. 반대쪽 끝에서 TeX 이 담을 수 있는 가장 큰 길이 \maxdimen 은 16383.99998pt, 미터로 고치면 약 5.76m 에 지나지 않습니다. 두 숫자는 모두 하나의 제약에서 나옵니다. 길이는 sp 단위의 정수이며 2^30 미만이어야 한다는 것입니다. 유럽 대륙 활판에서 온 dd(디도 포인트, 1157dd = 1238pt)와 cc(시세로, 1cc = 12dd)도 그대로 쓸 수 있지만 현대 문서에서는 거의 등장하지 않습니다.
em 과 ex 는 글꼴에 따라 달라집니다
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, 중간인 \:(4mu)는 amsmath 를 불러온 뒤에 쓸 수 있습니다.
% 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러버 길이 — plus 와 minus 가 실제로 하는 일
plus 는 늘어날 여지를, minus 는 줄어들 여지를 줍니다. 12pt 처럼 꿈쩍하지 않는 길이를 리지드 길이(rigid length), 1cm plus 2mm minus 1mm 처럼 여유가 있는 길이를 러버 길이(rubber length) 라고 하며, 뒤의 것은 “보통은 1cm, 필요하면 1.2cm 까지 늘고, 눌리면 0.9cm 까지 줄어든다”는 뜻입니다. TeX 에게 이것은 특별한 기능이 아닙니다. 행에서든 단락에서든 쪽에서든, 공백은 기본적으로 모두 늘고 주는 글루 입니다. 행이 좌우 여백에 딱 맞아떨어지는 것도 낱말 사이 공백이 러버 길이이기 때문입니다. 뒤집어 말하면 여유 없는 \vspace{12pt} 를 줄줄이 늘어놓는 일은 TeX 에게서 조정할 여지를 빼앗는 일입니다.
% 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 세 단계입니다. \hfil 은 plus 1fil, \hfill 은 plus 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 를 제치고 여유를 독차지하므로, 본문 속 글루는 자연 길이를 유지하고 남는 몫은 전부 쪽 아래로 몰립니다. 표준 클래스는 여기서 대신 선택해 줍니다. article, report, book 은 단면 문서라면 \raggedbottom 을, twoside 와 twocolumn 이라면 \flushbottom 을 부릅니다. article 의 기본값이 oneside 이므로, 기본 article 에서 \vspace 에 적은 plus・minus 는 쪽 맞춤에 거의 동원되지 않습니다. 쓰이게 하려면 \flushbottom 을 선언합니다.
\hspace 와 \hspace* 의 차이, 그리고 \hfill・\dotfill
행 안에 가로 공백을 넣는 것은 \hspace{길이} 입니다. \hspace{2cm} 라고 쓰면 2cm 가 벌어집니다. 단, 그 공백이 행의 가장자리에 놓이지 않아야 합니다. TeX 은 단락을 행으로 나눌 때마다 끊기는 자리에 붙어 있는 글루를 버립니다. 오른쪽 여백 밖으로 공백이 매달리거나 다음 행이 까닭 없이 들여쓰기되어 시작하지 않도록 하기 위한 규칙입니다. 별표 붙은 \hspace*{길이} 는 이 지점을 비켜 갑니다. 정의를 들여다보면 폭 0 인 \vrule 과 \nobreak 을 공백 바로 앞에 놓을 뿐입니다. 선은 글루가 아니라 박스 여서 버려지지 않고, 그 뒤의 공백은 더 이상 “끊기는 자리의 옆”이 아니게 됩니다. 첫 행에 들여쓰기를 강제로 넣어야 할 때 쓰는 것이 바로 이것입니다.
\hfill 은 \hspace{\fill} 과 같은 것으로, 양쪽에 있는 것을 행이 허락하는 한 멀리 밀어냅니다. 한 낱말은 행 머리에, 다른 하나는 행 끝에 두는 정석입니다. 이것도 글루라서 행 가장자리에서는 버려집니다. 반드시 남겨야 한다면 \hspace*{\fill} 이라고 씁니다. 빈칸 대신 채우고 싶다면 선을 긋는 \hrulefill 과 점을 늘어놓는 \dotfill 이 있으며, 둘 다 \hfill 에 TeX 의 리더 기구(\leaders・\cleaders)를 결합한 것입니다. 목차 항목과 쪽 번호 사이의 점선도, 기입란 아래의 밑줄도 이것으로 만듭니다. 작고 정해진 공백이라면 글꼴에 연동되는 \quad(1em), \qquad(2em), \, 가 글자 크기를 바꿔도 보이는 균형을 유지합니다. 6pt 라고 직접 박아 넣은 공백은 그렇지 못합니다.
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 1pt, 6pt plus 2pt minus 2pt, 12pt plus 4pt minus 4pt 입니다. 10pt 문서에서 \baselineskip 은 12pt 이므로 \bigskip 은 대략 한 줄에 해당합니다. 셋 모두 러버 길이라서 쪽 사정에 따라 조금 늘고 줄어듭니다. 여기서 앞 단락의 이야기가 그대로 적용됩니다. 이 셋은 별표 없는 \vspace 로 정의되어 있어서(\vspace\smallskipamount 등) 쪽 경계에서는 다른 글루와 똑같이 가차 없이 버려집니다. 제목 위에 넣어 둔 여백이 그 제목이 쪽 맨 위로 올라가는 순간 사라지는 이유가 이것입니다. 남겨야 한다면 \vspace*{\bigskipamount} 라고 씁니다. 세로 방향의 \fill 은 \vfill(= \vspace{\fill})로, 한 줄짜리 쪽을 세로 가운데에 두거나 서명란을 쪽 맨 아래까지 밀어내는 데 씁니다.
| 명령 | 들어가는 공백 | 끊기는 자리에서 버려지는가 |
|---|---|---|
\hspace{len} | 지정한 너비의 가로 글루 | 예, 행 가장자리에서 |
\hspace*{len} | 같은 너비. 앞에 폭 0 인 \vrule 을 둠 | 아니요 |
\hfill | \hspace{\fill} 과 동일. 0pt plus 1fill | 예 |
\hfil | 0pt 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 | 3pt plus 1pt minus 1pt 인 \vspace | 예 |
\medskip | 6pt plus 2pt minus 2pt 인 \vspace | 예 |
\bigskip | 12pt plus 4pt minus 4pt 인 \vspace. 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 같은 괄호 식도 쓸 수 있게 됩니다.
\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\textwidth, 2\baselineskip — 은 변경을 견딥니다. 세로 여백은 기성품인 \smallskip・\medskip・\bigskip 을 우선 쓰고 날것의 \vspace{12pt} 는 정말 필요할 때만 쓰면 문서 전체의 호흡이 고르게 맞습니다. 그리고 끊기는 자리를 넘어 반드시 남아야 하는 공백에만 별표를 붙입니다. 별표를 붙이지 않은 공백은 TeX 에게 버려도 좋다고 말해 둔 공백이기 때문입니다. 이 셋만 지켜도 “여기서만 공백이 사라진다”는 정체불명의 사고는 거의 일어나지 않습니다.