LaTeX의 description 환경은 itemize, enumerate와 나란한 세 번째 목록이면서도 설계 사상이 전혀 다릅니다. 표준 클래스의 정의를 열어 보면 description은 \labelwidth를 0pt로, \itemindent를 음수의 \leftmargin으로 설정합니다. 다시 말해 "표제어를 담는 칸"의 너비가 애초에 존재하지 않습니다. 이 한 줄이 description의 장점(표제어가 아무리 길어도 조판된다)과 가장 잘 알려진 골칫거리(긴 표제어가 설명을 옆으로 밀어낸다)를 동시에 설명합니다. 이 페이지에서는 이 환경이 무엇을 나타내기 위한 것인지, 굵은 글씨는 어디서 오는지, 그리고 enumitem의 style=이 그 밀어냄을 어떻게 다스리는지 살펴봅니다.
description은 무엇을 나타내기 위한 환경인가
description은 "낱말"과 "그 낱말의 설명"을 짝지어 늘어놓기 위한 환경입니다. itemize와 enumerate가 표시(점이나 번호)를 알아서 붙여 주는 것과 달리, description은 레이블을 여러분이 말로 주기를 기대합니다. \item의 선택 인수 [...]에 쓴 내용이 그대로 표제어가 됩니다. itemize와 enumerate에서 [...]는 "이 항목만 표시를 바꾼다"는 곁다리 기능이었지만, description에서는 그것이 핵심입니다. 용어집, 옵션 목록, 매개변수 설명, 등장인물 표 — "이름이 있고 거기에 설명이 딸린" 구조라면 이 환경이 정답입니다.
\begin{description}
\item[TeX] The typesetting system Knuth wrote.
\item[LaTeX] A document language built on top of TeX.
\item[CTAN] The worldwide archive network that distributes packages.
\end{description}이 구조는 HTML의 <dl>/<dt>/<dd>, 곧 정의 목록과 정확히 대응합니다. 그래서 description을 고르는 일에는 겉모습을 넘어선 의미가 있습니다. 원고 안에서 "이것은 정의다"라고 선언하는 셈이고, 변환 도구나 색인 생성 도구가 그 의도를 읽어 낼 수 있습니다. 반대로 \textbf{용어}\quad 설명처럼 손수 짜 놓으면 출력은 비슷해도 구조 정보는 사라집니다. itemize, enumerate와 마찬가지로 항목이 적어도 하나는 필요하며, 비운 채로 닫으면 ! LaTeX Error: Something's wrong--perhaps a missing \item.가 납니다.
굵은 글씨는 어디서 오는가(\descriptionlabel)
표제어가 굵게 나오는 것은 \item[...] 때문이 아니라 description에만 딸린 명령 \descriptionlabel 때문입니다. 표준 클래스에서의 정의는 \hspace\labelsep \normalfont\bfseries #1 한 줄이고, \bfseries가 바로 거기 적혀 있습니다. 이 구별은 확인해 볼 수 있습니다. itemize 안에 \item[Word]라고 쓰면 만들어진 PDF에는 본문용 로만체만 심어지고 굵은 글꼴은 전혀 나타나지 않습니다. 즉 \item[...]은 "표시를 갈아 끼우는" 기능일 뿐, 굵게 만드는 힘은 없습니다. description의 굵은 글씨는 그 환경이 \makelabel에 \descriptionlabel을 꽂아 넣음으로써 비로소 생깁니다.
그러므로 enumitem 없이 글꼴만 바꾸고 싶다면 \renewcommand로 \descriptionlabel을 다시 정의하는 것이 정공법입니다. 인수 #1이 표제어 텍스트입니다. 다음은 모든 표제어를 작은 대문자로 두는 예로, 원래 정의와 같은 여백을 지키려고 앞머리의 \hspace{\labelsep}을 남겨 두었습니다. \textsc를 \texttt(고정폭)나 \textit(이탤릭)로 바꾸면 원하는 모습이 됩니다. 한편 itemize는 계층마다 표시를, enumerate는 계층마다 번호 형태를 바꾸는 데 반해 description은 중첩해도 표제어의 체재가 달라지지 않습니다. \descriptionlabel은 하나뿐이므로 이 재정의는 문서의 모든 계층에 똑같이 듣습니다.
% the standard-class definition is:
% \newcommand*\descriptionlabel[1]{\hspace\labelsep \normalfont\bfseries #1}
\renewcommand{\descriptionlabel}[1]{%
{\hspace{\labelsep}\textsc{#1}}}긴 표제어가 설명을 밀어내는 까닭 — labelwidth가 0이기 때문
긴 표제어는 줄바꿈되지 않고, 설명 첫 줄을 자기 너비만큼 오른쪽으로 밀어냅니다. 원인은 latex.ltx에 있는 한 줄의 분기입니다. 레이블 상자가 \labelwidth보다 넓으면(\ifdim \wd\@tempboxa >\labelwidth) LaTeX은 고정 너비 상자를 포기하고 레이블을 자연스러운 너비 그대로 놓습니다. 그런데 description은 \labelwidth를 0pt로 두므로 아무리 짧은 낱말이라도 반드시 이 분기로 들어갑니다. 즉 description의 표제어는 애초에 고정 너비 칸에 들어 있지 않습니다. article에서 실측하니 \labelwidth는 0pt, \itemindent는 −25.00003pt(곧 −\leftmargin), \labelsep은 5pt였습니다.
실제로 조판해 재어 보면 표제어 뒤에는 언제나 5pt — 정확히 \labelsep만큼 — 의 여백이 들어가며, 원고에 \item[Term]body로 붙여 쓰든 \item[Term] body로 띄어 쓰든 같은 자리에 놓입니다. 그 여백은 원고의 공백이 아니라 \labelsep이 만드는 것이므로 붙여 쓴다고 해결되지 않습니다. 줄바꿈된 둘째 줄부터는 \leftmargin(25pt)까지 물러나므로, 표제어와 설명의 둘째 줄은 왼쪽 끝이 어긋나 계단처럼 보입니다. 더 밀어붙여 본문 폭보다 넓은 낱말을 놓으면 Overfull \hbox 경고와 함께 오른쪽 여백으로 넘칩니다. 실무의 판단은 이렇습니다. 표제어가 서너 낱말을 넘어가면 다음 절의 style=로 조판 방식 자체를 바꾸라.
enumitem의 font=과 style=으로 조판 방식 바꾸기
enumitem을 불러오면 description에도 옵션을 곧바로 건넬 수 있게 되어, font=이 표제어의 글꼴을, style=이 표제어와 본문의 배치 방식 자체를 정합니다. font=\sffamily\bfseries라고 쓰면 산세리프 굵은 글씨가, font=\ttfamily이면 고정폭이 됩니다. \descriptionlabel을 고쳐 쓰는 것보다 짧고, 목록마다 달리할 수 있다는 점이 진짜 장점입니다. leftmargin=, labelsep=, itemsep=처럼 다른 목록 유형과 공통인 키도 그대로 쓸 수 있습니다. 앞 절의 밀어내기 문제를 푸는 것은 style= 쪽입니다.
| style의 값 | 표제어가 길 때의 동작 |
|---|---|
standard | 표준 클래스와 같음. 레이블을 상자에 담아 짜고, 넘친 만큼 본문을 오른쪽으로 밈 |
unboxed | standard에 가깝지만 레이블을 상자에 담지 않음. 긴 낱말도 갑갑하지 않고 줄바꿈도 됨 |
nextline | 레이블이 여백에 들어가지 않으면 본문이 다음 줄에서 시작. 본문이 왼쪽 여백을 침범하지 않음 |
sameline | nextline과 비슷하지만, 레이블이 들어가지 않아도 본문은 같은 줄에 이어짐 |
multiline | 표제어를 labelwidth 너비 안에서 줄바꿈하고 필요하면 하이픈으로 쪼갬. 본문은 그 오른쪽에 정렬 |
같은 긴 표제어를 다섯 가지 style= 값으로 조판해 견주면 차이가 뚜렷이 드러납니다. nextline에서는 긴 낱말 뒤에서 본문이 다음 줄로 떨어지고, sameline에서는 같은 줄에 이어집니다. 짧은 낱말일 때는 둘 다 본문을 같은 줄에 두므로, 차이가 나타나는 것은 "들어가지 않을 때"뿐입니다. multiline은 극적입니다. 긴 낱말을 labelwidth 너비 안에서 줄바꿈하고 필요하면 하이픈까지 넣어 세로로 쌓습니다. 표제어가 긴 기술 문서 용어집에서 본문 왼쪽 끝을 일직선으로 맞추고 싶을 때 잘 듣습니다. 다만 그때는 labelwidth=를 명시하지 않으면 줄바꿈할 너비가 정해지지 않으므로 leftmargin=과 짝지어 지정하십시오.
\usepackage{enumitem}
% one list only
\begin{description}[font=\bfseries\sffamily, style=nextline, leftmargin=1.5cm]
\item[A term long enough to overrun its line]
the explanation begins on the next line instead of being shoved sideways
\item[Short] the explanation stays on this line
\end{description}
% or once in the preamble, for every description in the document
\setlist[description]{font=\sffamily\bfseries, style=nextline}대괄호의 함정과 레이블 생략
[와 ]는 선택 인수의 구분 기호이므로, 이를 문자로서 내고 싶을 때는 중괄호로 감싸 숨깁니다. 정규 표현식의 문자 클래스 [a-z]를 표제어로 삼으려면 \item[\texttt{[a-z]}]라고 씁니다. 닫는 괄호가 들어가면 더 조심해야 해서 \item[닫는 괄호 {]}]처럼 {]}로 적습니다. 반대 경우도 똑같이 위험합니다. 설명문이 [로 시작할 때는 \item {[}처럼 감싸지 않으면 LaTeX이 그것을 레이블의 시작으로 잘못 읽습니다. 프로그래밍 언어의 문법을 설명하는 문서에서는 이 둘이 끊임없이 나옵니다.
\begin{description}
\item[\texttt{[a-z]}] a character class; brackets in a label need braces
\item {[}this is how a body starting with a bracket is written
\end{description}레이블을 생략하면 그 항목에는 레이블이 붙지 않습니다. 표시도 들여쓰기의 실마리도 없는, 내어쓰기 문단 같은 항목이 됩니다. description에서는 레이블이야말로 핵심이므로, 의도한 경우가 아니라면 피하십시오. LaTeX이 기댈 만한 기본값이 없는 이상, 레이블은 언제나 직접 주어야 할 몫이라고 여기는 편이 안전합니다. 한 가지 더, 레이블 안에서 글꼴을 바꾸는 명령을 선언형으로 쓰면 기본 굵은 글씨를 덮어쓰므로, \item[{\ttfamily label}]처럼 명령째로 중괄호에 싸 두는 것이 안전한 습관입니다.
description과 2열 표, 어느 쪽을 쓸 것인가
실무의 분기점은 이렇습니다. 설명이 한 줄을 넘으면 description, 값이 짧고 고르며 세로로 훑어 읽히길 바란다면 표입니다. tabular의 2열은 "용어와 설명"을 짜기에 얼핏 안성맞춤이지만 약점이 셋 있습니다. 첫째, 페이지를 넘길 수 없습니다. longtable 같은 것을 끌어와야 합니다. 둘째, 열 너비를 직접 정해야 하고, p{5cm} 같은 고정값은 본문 폭이 바뀌는 순간 무너집니다. 셋째, 설명이 길어질수록 오른쪽 열만 아래로 늘어나 행과 행의 경계가 보이지 않게 됩니다. description은 어느 것도 겪지 않습니다. 문단으로 자연스럽게 흐르고, 페이지 나눔도 저절로 되며, 너비는 \textwidth를 따릅니다.
반대로, 값이 "형", "기본값", "범위"처럼 여러 속성을 지닌다면 그것은 이미 정의 목록이 아니라 표입니다. description은 "이름 → 설명"이라는 일대일 대응에만 어울립니다. 셋째 열이 필요해진 시점에 tabular로 옮기는 것이 옳은 판단이며, 억지로 \item[이름(형・기본값)]처럼 밀어 넣으면 표제어가 길어져 이 페이지 앞에서 본 밀어내기 문제로 곧장 되돌아갑니다.